def decorated_function(env, csrf_clerk): get_vars = util.retrieve_get_vars(env) post_vars = util.retrieve_post_vars(env) session = turbo_session.get_session(env) account = turbo_session.retrieve_oauth_account(session) # Start OAuth cookie_set = int(get_vars.get('cookie_set', [0])[0]) # Failed to set cookie, tell user to enable cookies if(account is None and min_access_level >= ACL.turbo and cookie_set == 1): return error_view('Login Error', 'Failed to create session. Try to enable ' ' cookies for this site.') elif(account is None and min_access_level >= ACL.turbo): # Show Auth Error in headless mode if(headless): return error_view('Auth Error', 'You are not logged in.', nav, headless=True) redirect_uri = turbo_views['oauth-callback'].uri oauth = turbo_session.OAuth2Session( config.mastodon.client_id, redirect_uri=redirect_uri, scope=config.mastodon.scope) authorization_url, state = oauth.authorization_url( config.mastodon.authorize_url, turbo_session.generate_state(env, csrf_clerk) ) status = '307 Temporary Redirect' response_body = '' response_headers = [('Location', str(authorization_url))] # Redirect to url without cookie_set parameter elif(cookie_set == 1): status = '307 Temporary Redirect' response_body = '' response_headers = [ ('Location', util.build_url(env['PATH_INFO'])) ] # Display View else: user = User.create(account) access_level = User.get_access_level(user) if access_level < min_access_level: return error_view('Missing Privileges', 'You do not have the required ' 'permissions to access this.', access_level=access_level) response_body, response_headers, status = func( env, get_vars, post_vars, csrf_clerk, session, user ) return response_body, response_headers, status
def generate_html(page_name, user=None, **kwargs): access_level = kwargs.get('access_level', User.get_access_level(user)) page_item = this.items.get(page_name) hover = ' hover' if kwargs.get('expanded', False) else '' html = f'\t<ul id="nav" class="no-js{hover}" aria-haspopup="true">\n' html += '\t\t<li class="arrow down"><span></span></li>\n' for name in this.items: item = this.items[name] view = item.turbo_view if item.max_access_level >= access_level >= item.min_access_level: if name == page_name: html += f'\t\t<li><span>{view.display_name}</span></li>\n' else: item_uri = view.path if not item_uri: item_uri = view.uri # Add redirect_to for current page to the login nav-item if name == 'login' and page_item is not None: redirect_to = quote_plus(page_item.turbo_view.path) item_uri = f'{view.path}?redirect_to={redirect_to}' html += '\t\t<li>' html += f'<a href="{item_uri}">{view.display_name}</a>' html += '</li>\n' html += '\t\t<li class="arrow up"><span></span></li>\n\t</ul>' return html
def init_context(self, env, user, connection_id): return { 'env': env, 'user': user, 'access_level': User.get_access_level(user), 'connection_id': connection_id, }
def discord_callback_view(env, get_vars, post_vars, csrf_clerk, session, user): redirect_uri = turbo_views['discord-callback'].uri authorization_response = redirect_uri + '?' + env['QUERY_STRING'] discord_user_url = config.discord.api_endpoint + '/users/@me' access_level = User.get_access_level(user) try: oauth = turbo_session.OAuth2Session(config.discord.client_id, redirect_uri=redirect_uri, scope=config.discord.scope) oauth_state = turbo_session.retrieve_oauth_state( get_vars.get('state', [''])[0]) if oauth_state and csrf_clerk.validate('oauth-authorization', oauth_state[0]): token = oauth.fetch_token( config.discord.token_url, authorization_response=authorization_response, client_secret=config.discord.client_secret) discord_user = oauth.get(discord_user_url).json() if discord_user is not None and discord_user.get('id') is not None: # If people link their discord to another account, # the old one should lose its turbo role discord_id = int(discord_user['id']) if user.discord_id and user.discord_id != discord_id: if not discord.remove_turbo_role(user.discord_id): return error_view( 'Unexpected error', 'Failed to reassign TURBO status to ' 'a different Discord account. ' 'Please try again.') user.set_discord_id(discord_id) discord.add_turbo_role(discord_id, token) redirect_to = str(oauth_state[1]) if redirect_to.startswith('/'): redirect_to = util.build_url(redirect_to) status = '307 Temporary Redirect' response_body = '' response_headers = [('Location', redirect_to)] else: return error_view('Unexpected error', 'Failed to retrieve Discord user details.', access_level=access_level) else: return error_view('CSRF Verfication failed', 'Failed to authorize Discord account due to a ' 'CSRF verfication error, try again.', access_level=access_level) except OAuth2Error as error: # Might indicate a "deny" on granting access to the app logger.info(f'OAuth 2.0 Error occured: {error}', exc_info=config.debug_mode) return error_view('OAuth Error', 'Failed to authorize Discord account, try again.', access_level=access_level) else: # Normal function return without errors return response_body, response_headers, status
def init_context(self): user = self.authenticate(self.env) access_level = User.get_access_level(user) self.context = { 'user': user, 'access_level': access_level, }
def decorated_function(env, csrf_clerk): post_vars = util.retrieve_post_vars(env) session = turbo_session.get_session(env) account = turbo_session.retrieve_oauth_account(session) status = '200 OK' if account is None: return {'error': 'Couldn\'t authenticate user.'}, status csrf_token = post_vars.get('csrf_token', [''])[0] if csrf_check and not csrf_clerk.validate(session, csrf_token): return {'error': 'CSRF token verification failed.'}, status user = User.create(account) access_level = User.get_access_level(user) if access_level < min_access_level: return {'error': 'You do not have the required permissions.'} response = func(post_vars, user) if csrf_check: # create new csrf token for next api call response['csrf_token'] = csrf_clerk.register(session) return response, status
def open_websocket(self, env): context = None try: user = self.authenticate(env) access_level = User.get_access_level(user) if access_level < self.min_access_level: return uwsgi.websocket_handshake() util.print_info('Opening websocket connection', False) client_count = self.redis.get('websocket-clients') if client_count: client_count = int(client_count.decode('utf-8')) if client_count >= config.websockets_max_clients: raise ClientError('No available slots.') self.redis.incr('websocket-clients') context = True channel = self.redis.pubsub() channel.subscribe(self.name) websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() context = self.init_context(env, user, redis_fd) while True: ready = gevent.select.select([websocket_fd, redis_fd], [], [], 4.0) if not ready[0]: # send ping on timeout uwsgi.websocket_recv_nb() for fd in ready[0]: if fd == websocket_fd: # client message context = self.fetch_and_handle_client_message(context) elif fd == redis_fd: # channel message message = channel.parse_response() if message[0] == b'message': context = self.handle_channel_message( context, message[2]) except ClientTimeout: util.print_info('Websocket connection client timeout.') except ClientDisconnect: util.print_info('Websocket connection client disconnected.') except ClientError as error: util.print_exception('Websocket client error', error, False, print_traceback=False) except IOError as error: # Socket Error util.print_exception('Websocket connection closed', error, False, print_traceback=False) except DBError as error: # Database Error util.print_exception('Database Error occured: ', error) except OAuth2Error as error: # OAuth 2.0 Error util.print_exception('OAuth 2.0 Error occured: ', error) except Exception as error: # Unknown Exception util.print_exception('Unexpected Error occured: ', error, False) finally: self.cleanup(context)
def authenticate(self, env): session = turbo_session.get_session(env) account = turbo_session.retrieve_oauth_account(session) if account: return User.create(account) return None