Пример #1
0
        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
Пример #2
0
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
Пример #3
0
 def init_context(self, env, user, connection_id):
     return {
         'env': env,
         'user': user,
         'access_level': User.get_access_level(user),
         'connection_id': connection_id,
     }
Пример #4
0
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
Пример #5
0
    def init_context(self):
        user = self.authenticate(self.env)
        access_level = User.get_access_level(user)

        self.context = {
            'user': user,
            'access_level': access_level,
        }
Пример #6
0
 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
Пример #7
0
    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)
Пример #8
0
 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