mirror of
https://github.com/ihabunek/toot.git
synced 2025-05-18 00:58:30 -04:00
Add alternate redirect_uri
support for broken instances
Pixelfed instances do not handle OOB OAuth correctly meaning you can't currently login to them using `toot` (e.g. https://github.com/pixelfed/pixelfed/issues/2522 ) This is a fudge to workaround that by allowing you to specify an alternate `redirect_uri` for broken servers which can take the HTTP redirect issued by Pixelfed and let you grab the code. If you don't have a handy HTTP server, you can use `http://localhost` and your browser (at least Safari and Chrome) will have the code in the address bar for copying and pasting into `toot`.
This commit is contained in:
parent
1368a89125
commit
727b3cfad2
@ -17,6 +17,7 @@ class App(NamedTuple):
|
||||
base_url: str
|
||||
client_id: str
|
||||
client_secret: str
|
||||
redirect_uri: str
|
||||
|
||||
|
||||
class User(NamedTuple):
|
||||
|
10
toot/api.py
10
toot/api.py
@ -77,12 +77,12 @@ def _tag_action(app, user, tag_name, action) -> Response:
|
||||
return http.post(app, user, url)
|
||||
|
||||
|
||||
def create_app(base_url):
|
||||
def create_app(base_url, redirect_uri):
|
||||
url = f"{base_url}/api/v1/apps"
|
||||
|
||||
json = {
|
||||
'client_name': CLIENT_NAME,
|
||||
'redirect_uris': 'urn:ietf:wg:oauth:2.0:oob',
|
||||
'redirect_uris': redirect_uri,
|
||||
'scopes': SCOPES,
|
||||
'website': CLIENT_WEBSITE,
|
||||
}
|
||||
@ -157,7 +157,7 @@ def fetch_app_token(app):
|
||||
"client_id": app.client_id,
|
||||
"client_secret": app.client_secret,
|
||||
"grant_type": "client_credentials",
|
||||
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
|
||||
"redirect_uri": app.redirect_uri,
|
||||
"scope": "read write"
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ def get_browser_login_url(app: App) -> str:
|
||||
"""Returns the URL for manual log in via browser"""
|
||||
return "{}/oauth/authorize/?{}".format(app.base_url, urlencode({
|
||||
"response_type": "code",
|
||||
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
|
||||
"redirect_uri": app.redirect_uri,
|
||||
"scope": SCOPES,
|
||||
"client_id": app.client_id,
|
||||
}))
|
||||
@ -197,7 +197,7 @@ def request_access_token(app: App, authorization_code: str):
|
||||
'client_id': app.client_id,
|
||||
'client_secret': app.client_secret,
|
||||
'code': authorization_code,
|
||||
'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
|
||||
'redirect_uri': app.redirect_uri,
|
||||
}
|
||||
|
||||
return http.anon_post(url, data=data, allow_redirects=False).json()
|
||||
|
14
toot/auth.py
14
toot/auth.py
@ -12,22 +12,22 @@ def find_instance(base_url: str) -> Instance:
|
||||
raise ConsoleError(f"Instance not found at {base_url}")
|
||||
|
||||
|
||||
def register_app(domain: str, base_url: str) -> App:
|
||||
def register_app(domain: str, base_url: str, redirect_uri: str) -> App:
|
||||
try:
|
||||
response = api.create_app(base_url)
|
||||
response = api.create_app(base_url, redirect_uri)
|
||||
except ApiError:
|
||||
raise ConsoleError("Registration failed.")
|
||||
|
||||
app = App(domain, base_url, response['client_id'], response['client_secret'])
|
||||
app = App(domain, base_url, response['client_id'], response['client_secret'], redirect_uri)
|
||||
config.save_app(app)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def get_or_create_app(base_url: str) -> App:
|
||||
def get_or_create_app(base_url: str, redirect_uri: str) -> App:
|
||||
instance = find_instance(base_url)
|
||||
domain = _get_instance_domain(instance)
|
||||
return config.load_app(domain) or register_app(domain, base_url)
|
||||
return config.load_app(domain, redirect_uri) or register_app(domain, base_url, redirect_uri)
|
||||
|
||||
|
||||
def create_user(app: App, access_token: str) -> User:
|
||||
@ -53,8 +53,8 @@ def login_username_password(app: App, email: str, password: str) -> User:
|
||||
def login_auth_code(app: App, authorization_code: str) -> User:
|
||||
try:
|
||||
response = api.request_access_token(app, authorization_code)
|
||||
except Exception:
|
||||
raise ConsoleError("Login failed")
|
||||
except Exception as e:
|
||||
raise ConsoleError("Login failed", e)
|
||||
|
||||
return create_user(app, response["access_token"])
|
||||
|
||||
|
@ -77,9 +77,11 @@ you need to paste here.""".replace("\n", " ")
|
||||
|
||||
@cli.command()
|
||||
@instance_option
|
||||
def login(base_url: str):
|
||||
@click.option("--redirect", "-r", "redirect_uri", help="Redirect URI to use instead of OOB", prompt=True, default="urn:ietf:wg:oauth:2.0:oob")
|
||||
def login(base_url: str, redirect_uri: str):
|
||||
"""Log into an instance using your browser (recommended)"""
|
||||
app = get_or_create_app(base_url)
|
||||
app = get_or_create_app(base_url, redirect_uri)
|
||||
# `redirect_uri` is now stored in `app` for future use / saving.
|
||||
url = api.get_browser_login_url(app)
|
||||
|
||||
click.echo(click.wrap_text(LOGIN_EXPLANATION))
|
||||
|
@ -87,10 +87,17 @@ def get_user_app(user_id: str):
|
||||
return extract_user_app(load_config(), user_id)
|
||||
|
||||
|
||||
def load_app(instance: str) -> Optional[App]:
|
||||
def load_app(instance: str, redirect_uri: str) -> Optional[App]:
|
||||
config = load_config()
|
||||
if instance in config['apps']:
|
||||
return App(**config['apps'][instance])
|
||||
a = App(**config['apps'][instance])
|
||||
# Not sure about this bit - if an app was stored without a `redirect_uri`, should
|
||||
# loading update it to OOB (the previous default) or to the requested `redirect_uri`?
|
||||
# Stick to OOB for now because presumably if we've saved the app, the login must
|
||||
# have worked with OOB and there's no need for a `redirect_uri` update. Maybe?
|
||||
if a.redirect_uri == "":
|
||||
a.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
||||
return a
|
||||
|
||||
|
||||
def load_user(user_id: str, throw=False):
|
||||
|
Loading…
x
Reference in New Issue
Block a user