ovos-backend-manager/ovos_backend_manager/oauth.py
2023-04-08 00:50:24 +01:00

160 lines
5.6 KiB
Python

import json
import os
from oauthlib.oauth2 import WebApplicationClient
from ovos_backend_manager.configuration import CONFIGURATION, DB
from pywebio.input import actions, input_group, input, TEXT
from pywebio.output import use_scope, popup, put_image, put_link, put_code, put_text, put_table, put_markdown
def get_oauth_data(app_id=None):
data = {}
if app_id:
data = DB.get_oauth_app(app_id)
data = data or {'auth_endpoint': "https://",
'token_endpoint': "https://",
'refresh_endpoint': "https://"}
if "callback_endpoint" not in data:
backend_url = f"http://0.0.0.0:{CONFIGURATION['backend_port']}/{CONFIGURATION['api_version']}"
data["callback_endpoint"] = f"{backend_url}/auth/callback/{app_id or '...'}"
with use_scope("main_view", clear=True):
return input_group('Settings', [
input("Name", value=app_id or "...",
type=TEXT, name="oauth_service"),
input("Client ID", value=data.get("client_id", ""),
type=TEXT, name='client_id'),
input("Client Secret", value=data.get("client_secret", ""),
type=TEXT, name='client_secret'),
input("Auth Endpoint", value=data.get("auth_endpoint", ""),
type=TEXT, name='auth_endpoint'),
input("Token Endpoint", value=data.get("token_endpoint", ""),
type=TEXT, name='token_endpoint'),
input("Refresh Endpoint", value=data.get("refresh_endpoint", ""),
type=TEXT, name='refresh_endpoint'),
input("Callback Endpoint", value=data["callback_endpoint"],
type=TEXT, name='callback_endpoint'),
input("Scope", value=data.get("scope", ""),
type=TEXT, name='scope')
])
def authorize_app(data):
callback_endpoint = f"http://0.0.0.0:36535/auth/callback/{data['oauth_service']}"
client = WebApplicationClient(data["client_id"])
request_uri = client.prepare_request_uri(
data["auth_endpoint"],
redirect_uri=data.get("callback_endpoint") or callback_endpoint,
show_dialog=True,
state=data['oauth_service'],
scope=data["scope"],
)
with popup(f"{data['oauth_service']}"):
put_link("Authorize", request_uri, new_window=True)
def _render_app(app_id):
with use_scope("main_view", clear=True):
data = DB.get_oauth_app(app_id)
put_markdown(f'# {app_id.title()}')
put_table([
['Client ID', data["client_id"]],
['Client Secret', data["client_secret"]],
['Scope', data["scope"]]
])
put_markdown(f'### OAuth Endpoints')
put_table([
['Auth', data["auth_endpoint"]],
['Token', data["token_endpoint"]],
['Refresh', data["refresh_endpoint"]],
['Callback', data["callback_endpoint"]],
])
def app_menu(app_id, back_handler=None):
with use_scope("logo", clear=True):
img = open(f'{os.path.dirname(__file__)}/res/oauth.png', 'rb').read()
put_image(img)
_render_app(app_id)
buttons = [
{'label': "Configure", 'value': "oauth"},
]
tok = DB.get_oauth_token(app_id)
if tok:
buttons.append({'label': "View Token", 'value': "token"})
buttons.append({'label': "Refresh Token", 'value': "refresh"})
else:
buttons.append({'label': "Authorize", 'value': "auth"})
buttons.append({'label': "Delete", 'value': "delete"})
if back_handler:
buttons.insert(0, {'label': '<- Go Back', 'value': "main"})
opt = actions(label=f"What would you like to do with {app_id}?",
buttons=buttons)
if opt == "main":
with use_scope("main_view", clear=True):
oauth_menu(back_handler=back_handler)
return
elif opt == "token":
with popup("OAuth Token"):
put_code(json.dumps(tok, indent=4), language="json")
elif opt == "auth" or opt == "refresh": # TODO special refresh handling (?)
data = DB.get_oauth_app(app_id)
authorize_app(data)
elif opt == "oauth":
data = get_oauth_data(app_id)
app_id = data.pop("oauth_service")
DB.update_oauth_app(app_id, **data)
with popup(app_id):
put_text(f"{app_id} oauth settings updated!")
elif opt == "delete":
DB.delete_oauth_app(app_id)
with popup(app_id):
put_text(f"{app_id} oauth settings deleted!")
oauth_menu(back_handler=back_handler)
return
else:
app_id = opt
app_menu(app_id, back_handler=back_handler)
def oauth_menu(back_handler=None):
with use_scope("logo", clear=True):
img = open(f'{os.path.dirname(__file__)}/res/oauth.png', 'rb').read()
put_image(img)
with use_scope("main_view", clear=True):
pass
buttons = [{'label': 'New App', 'value': "new"}]
for app in DB.list_oauth_apps():
app_id = app.pop("token_id")
data = app
buttons.append({'label': app_id, 'value': data})
if back_handler:
buttons.insert(0, {'label': '<- Go Back', 'value': "main"})
opt = actions(label="What would you like to do?",
buttons=buttons)
if opt == "new":
data = get_oauth_data()
app_id = data.pop("oauth_service")
DB.add_oauth_app(app_id, **data)
authorize_app(data)
elif opt == "main":
with use_scope("main_view", clear=True):
if back_handler:
back_handler()
return
else:
app_menu(opt, back_handler=back_handler)
return
oauth_menu(back_handler=back_handler)