import os from typing import List, Tuple from flask import session, url_for from requests_oauthlib import OAuth2Session from shared import configuration from shared_web import logger API_BASE_URL = 'https://discordapp.com/api' AUTHORIZATION_BASE_URL = API_BASE_URL + '/oauth2/authorize' TOKEN_URL = API_BASE_URL + '/oauth2/token' OAUTH2_CLIENT_ID = configuration.get('oauth2_client_id') OAUTH2_CLIENT_SECRET = configuration.get('oauth2_client_secret') def setup_authentication() -> Tuple[str, str]: scope = ['identify', 'guilds', 'guilds.join'] discord = make_session(scope=scope) return discord.authorization_url(AUTHORIZATION_BASE_URL) def setup_session(url: str) -> None: discord = make_session(state=session.get('oauth2_state')) token = discord.fetch_token( TOKEN_URL, client_secret=OAUTH2_CLIENT_SECRET, authorization_response=url) session.permanent = True session['oauth2_token'] = token discord = make_session(token=session.get('oauth2_token')) user = discord.get(API_BASE_URL + '/users/@me').json() session['id'] = user['id'] session['discord_id'] = user['id'] session['discord_locale'] = user['locale'] guilds = discord.get(API_BASE_URL + '/users/@me/guilds').json() wrong_guilds = False # protect against an unexpected response from discord session['in_guild'] = False session['admin'] = False session['demimod'] = False for guild in guilds: if isinstance(guild, dict) and 'id' in guild: if guild['id'] == configuration.get('guild_id'): session['admin'] = (guild['permissions'] & 0x10000000) != 0 # Check for the MANAGE_ROLES permissions on Discord as a proxy for "is admin". session['demimod'] = (guild['permissions'] & 0x20000) != 0 # Check for the "Mention @everyone" permissions on Discord as a proxy for "is demimod". session['in_guild'] = True else: wrong_guilds = True if wrong_guilds: logger.warning('auth.py: unexpected discord response. Guilds: {g}'.format(g=guilds)) def add_to_guild() -> None: discord = make_session(token=session.get('oauth2_token')) if not session['in_guild']: discord.put('/guilds/{guild}/members/{user}'.format(guild=configuration.get('guild_id'), user=session['discord_id'])) def make_session(token: str = None, state: str = None, scope: List[str] = None) -> OAuth2Session: return OAuth2Session( client_id=OAUTH2_CLIENT_ID, token=token, state=state, scope=scope, redirect_uri=redirect_uri(), auto_refresh_kwargs={ 'client_id': OAUTH2_CLIENT_ID, 'client_secret': OAUTH2_CLIENT_SECRET, }, auto_refresh_url=TOKEN_URL, token_updater=token_updater) def token_updater(token: str) -> None: session['oauth2_token'] = token def redirect_uri() -> str: uri = url_for('authenticate_callback', _external=True) if 'http://' in uri: os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = 'true' return uri def logout() -> None: session['admin'] = None session['demimod'] = None session['id'] = None session['discord_id'] = None session['logged_person_id'] = None session['person_id'] = None session['mtgo_username'] = None session['discord_locale'] = None