Skip to content

Commit

Permalink
Custom MFA (#52)
Browse files Browse the repository at this point in the history
* custom MFA handler

* more details on mfa handler

* fix typo

* bump version
  • Loading branch information
matin authored Mar 17, 2024
1 parent 7ba3ec6 commit 316787d
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 8 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ garth.login(email, password)
garth.save("~/.garth")
```

### Custom MFA handler

There's already a default MFA handler that prompts for the code in the
terminal. You can provide your own handler. The handler should return the
MFA code through your custom prompt.

```python
garth.login(email, password, prompt_mfa=lambda: input("Enter MFA code: "))
```

### Configure

#### Set domain for China
Expand Down
6 changes: 4 additions & 2 deletions garth/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,10 @@ def delete(self, *args, **kwargs) -> Response:
def put(self, *args, **kwargs) -> Response:
return self.request("PUT", *args, **kwargs)

def login(self, *args):
self.oauth1_token, self.oauth2_token = sso.login(*args, client=self)
def login(self, *args, **kwargs):
self.oauth1_token, self.oauth2_token = sso.login(
*args, **kwargs, client=self
)

def refresh_oauth2(self):
assert self.oauth1_token
Expand Down
16 changes: 11 additions & 5 deletions garth/sso.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re
import time
from typing import Dict, Optional, Tuple
from typing import Callable, Dict, Optional, Tuple
from urllib.parse import parse_qs

import requests
Expand Down Expand Up @@ -40,7 +40,11 @@ def __init__(


def login(
email: str, password: str, /, client: Optional["http.Client"] = None
email: str,
password: str,
/,
client: Optional["http.Client"] = None,
prompt_mfa: Callable = lambda: input("MFA code: "),
) -> Tuple[OAuth1Token, OAuth2Token]:
client = client or http.client

Expand Down Expand Up @@ -92,7 +96,7 @@ def login(

# Handle MFA
if "MFA" in title:
handle_mfa(client, SIGNIN_PARAMS)
handle_mfa(client, SIGNIN_PARAMS, prompt_mfa)
title = get_title(client.last_resp.text)

assert title == "Success"
Expand Down Expand Up @@ -142,9 +146,11 @@ def exchange(oauth1: OAuth1Token, client: "http.Client") -> OAuth2Token:
return OAuth2Token(**set_expirations(token))


def handle_mfa(client: "http.Client", signin_params: dict) -> None:
def handle_mfa(
client: "http.Client", signin_params: dict, prompt_mfa: Callable
) -> None:
csrf_token = get_csrf_token(client.last_resp.text)
mfa_code = input("Enter MFA code: ")
mfa_code = prompt_mfa()
client.post(
"sso",
"/sso/verifyMFA/loginEnterMfaCode",
Expand Down
2 changes: 1 addition & 1 deletion garth/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.4.44"
__version__ = "0.4.45"

0 comments on commit 316787d

Please sign in to comment.