Example #1
0
async def bank(request: HTTPConnection):
    login_form = LoginForm()
    transfer_form = TransferForm()

    current_user = request.cookies.get("username")

    return templates.TemplateResponse(
        "bank.j2",
        {
            "request":
            request,
            "login_form":
            login_form,
            "transfer_form":
            transfer_form,
            "login_url":
            request.url_for("bank_login"),
            "transfer_url":
            request.url_for("bank_transfer"),
            "current_user":
            current_user,
            "transactions":
            [] if current_user is None else transactions[current_user],
        },
    )
Example #2
0
async def auth_cb(request: HTTPConnection):
    token = await oauth.discord.authorize_access_token(request)
    resp = await oauth.discord.get(DISCORD_API_BASE + "/users/@me", token=token, auth=UNSET)
    user = resp.json()
    request.session["discord_id"] = int(user["id"])
    request.session["discord_username"] = user["username"]
    return RedirectResponse(url="/")
Example #3
0
    async def authenticate(
            self,
            conn: HTTPConnection) -> Optional[Tuple[AuthCredentials, User]]:
        if 'token' in conn.cookies:
            token = json.loads(conn.cookies.get('token'))
            user = json.loads(conn.cookies.get('user'))

            expires_at = datetime.utcfromtimestamp(token['expires_at'])
            refresh_token = token['refresh_token']
            now = datetime.now()

            # Check token expiration
            if expires_at > now:
                token, user = await self._refresh_access_token(refresh_token)
                self._update_auth_cookies(conn, token, user)
            self._add_data_to_session(conn, token, user)

            # Check user in database
            user_model = await self._check_user_in_db(user)

            # Store token and user in global context
            conn.scope['user'] = user
            conn.scope['token'] = token

            return AuthCredentials(['authenticated']), user_model
        return
Example #4
0
async def validate_refresh_token(conn: HTTPConnection):
    """ Validate the refresh token """
    user = conn.session.get("user", {})
    if user.get("exp", 0) < time.time():
        # User is expired, remove their session
        if user:
            del conn.session["user"]

        # The token is expired, try to refresh
        refresh_token = conn.session.get("refresh_token")
        if refresh_token:
            metadata = await oauth.storium.load_server_metadata()
            async with oauth.storium._get_oauth_client(  # pylint:disable=protected-access
                **metadata
            ) as client:
                try:
                    token = await client.refresh_token(
                        metadata["token_endpoint"], refresh_token
                    )
                    conn.session["refresh_token"] = token.get("refresh_token")

                    # Refresh was successful, set user session
                    user = await oauth.storium.parse_id_token(conn, token)
                    conn.session["user"] = dict(user)
                except OAuthError as exc:
                    # The refresh token has likely expired
                    logger.error(exc)
    async def authenticate(
            self, conn: HTTPConnection) -> Tuple[bool, Optional[User]]:
        """
        Main function that AuthenticationMiddleware uses from this backend.
        Should return whether request is authenticated based on credentials and
        if it was, return also user instance.

        :param conn: HTTPConnection of the current request-response cycle
        :return: 2-tuple: is authenticated & user instance if exists
        """
        authorization: str = conn.headers.get("Authorization")
        if not authorization:
            return False, None
        scheme, credentials = get_authorization_scheme_param(authorization)
        if not (authorization and scheme and credentials):
            raise AuthenticationError("Not authenticated")
        if scheme.lower() != "token":
            raise AuthenticationError("Invalid authentication credentials")

        token = await Token.get(
            key=credentials,
            is_active=True,
            expires={"$not": {
                "$lt": get_now()
            }},
        )
        if token is None:
            return False, None
        conn.scope["token"] = token

        user = await User.get(id=token.user_id)
        if user is None:
            return False, None

        return True, user
    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] not in ("http", "websocket"):  # pragma: no cover
            await self.app(scope, receive, send)
            return

        connection = HTTPConnection(scope)
        initial_session_was_empty = True

        if self.session_cookie in connection.cookies:
            data = connection.cookies[self.session_cookie].encode("utf-8")
            try:
                jwt_payload = jwt.decode(
                    data,
                    str(
                        self.jwt_secret.decode
                        if self.jwt_secret.decode
                        else self.jwt_secret.encode
                    ),
                )
                jwt_payload.validate_exp(time.time(), 0)
                scope["session"] = jwt_payload
                initial_session_was_empty = False
            except (BadSignatureError, ExpiredTokenError):
                scope["session"] = {}
        else:
            scope["session"] = {}

        async def send_wrapper(message: Message) -> None:
            if message["type"] == "http.response.start":
                if scope["session"]:
                    if "exp" not in scope["session"]:
                        scope["session"]["exp"] = int(time.time()) + self.max_age
                    data = jwt.encode(
                        self.jwt_header, scope["session"], str(self.jwt_secret.encode)
                    )

                    headers = MutableHeaders(scope=message)
                    header_value = "%s=%s; path=/; Max-Age=%d; %s" % (
                        self.session_cookie,
                        data.decode("utf-8"),
                        self.max_age,
                        self.security_flags,
                    )
                    if self.domain:  # pragma: no cover
                        header_value += f"; domain={self.domain}"
                    headers.append("Set-Cookie", header_value)
                elif not initial_session_was_empty:
                    # The session has been cleared.
                    headers = MutableHeaders(scope=message)
                    header_value = "%s=%s; %s" % (
                        self.session_cookie,
                        "null; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT;",
                        self.security_flags,
                    )
                    if self.domain:  # pragma: no cover
                        header_value += f"; domain={self.domain}"
                    headers.append("Set-Cookie", header_value)
            await send(message)

        await self.app(scope, receive, send_wrapper)
Example #7
0
def prepare_resolver(monkeypatch):
    resolvers._collect_predicate_names = lambda info: [
        'asn', 'prefix', 'ipLast'
    ]

    mock_database_query = Mock(spec=RPSLDatabaseQuery)
    monkeypatch.setattr('irrd.server.graphql.resolvers.RPSLDatabaseQuery',
                        lambda **kwargs: mock_database_query)
    mock_database_query.columns = RPSLDatabaseQuery.columns

    mock_query_resolver = Mock(spec=QueryResolver)
    monkeypatch.setattr(
        'irrd.server.graphql.resolvers.QueryResolver',
        lambda preloader, database_handler: mock_query_resolver)

    app = Mock(state=Mock(
        database_handler=Mock(spec=DatabaseHandler),
        preloader=Mock(spec=Preloader),
    ))
    app.state.database_handler.execute_query = lambda query, refresh_on_error: MOCK_RPSL_DB_RESULT

    info = Mock()
    info.context = {}
    info.field_nodes = [Mock(selection_set=Mock(selections=Mock()))]
    info.context['request'] = HTTPConnection({
        'type': 'http',
        'client': ('127.0.0.1', '8000'),
        'app': app,
    })

    yield info, mock_database_query, mock_query_resolver
 def get_request_object(scope, receive,
                        send) -> Union[Request, HTTPConnection]:
     # here we instantiate HTTPConnection instead of a Request object
     # because only headers are needed so that's sufficient.
     # If you need the payload etc for your plugin
     # instantiate Request(scope, receive, send)
     return HTTPConnection(scope)
Example #9
0
    async def __call__(self, scope: Scope, receive: Receive,
                       send: Send) -> None:
        if scope["type"] not in ("http", "websocket"):  # pragma: no cover
            await self.app(scope, receive, send)
            return

        connection = HTTPConnection(scope)
        initial_session_was_empty = True
        session_id = None

        if self.session_cookie in connection.cookies:
            session_id = connection.cookies[self.session_cookie]
            try:
                scope["session"] = await self.get_session(session_id)
                initial_session_was_empty = False
            except Exception:
                scope["session"] = {}
        else:
            scope["session"] = {}

        async def send_wrapper(message: Message) -> None:
            nonlocal session_id
            if message["type"] == "http.response.start":
                if scope["session"]:
                    session_id = session_id or uuid.uuid4().hex
                    # Persist session
                    await self.save_session(session_id, scope["session"])
                    self.set_cookie(message=message, value=session_id)
                elif not initial_session_was_empty:
                    # Clear session
                    await self.delete_session(session_id)
                    self.set_cookie(message=message, value="null", max_age=-1)
            await send(message)

        await self.app(scope, receive, send_wrapper)
Example #10
0
    async def authenticate(self, request: HTTPConnection):
        if "discord_id" not in request.session:
            request.session.pop("user", None)
            return

        user = request.session.get("user")
        if not user:
            uid = request.session["discord_id"]

            if uid not in settings.LADS:
                return
            user = {
                "discord_id": uid,
                "username": request.session["discord_username"],
            }
            request.session["user"] = user

        username, discord_id = (
            user["username"],
            user["discord_id"],
        )

        creds = ["authenticated"]

        return AuthCredentials(creds), User(username, discord_id)
    async def authenticate(self, request: HTTPConnection):
        if "discord_id" not in request.session:
            request.session.pop("user", None)
            return

        user = request.session.get("user")
        if not user:
            db_user = await DBUser.get(request.session["discord_id"])
            log.info("First time adding user info for %s, user: %s",
                     request.session["discord_id"], db_user)

            if db_user is None:
                log.info("User %s was not in the database, rejecting",
                         request.session["discord_id"])
                request.session.pop("discord_id", None)
                return
            user = {
                "discord_id": db_user.discord_id,
                "is_admin": db_user.is_admin,
                "username": db_user.username,
            }
            request.session["user"] = user

        username, discord_id, is_admin = (
            user["username"],
            user["discord_id"],
            user["is_admin"],
        )

        creds = ["authenticated"]
        if is_admin:
            creds.append("admin")

        return AuthCredentials(creds), User(username, discord_id, is_admin)
Example #12
0
    async def post(self, request: HTTPConnection):
        id = request.path_params["id"]

        blog = await Blog.get(id)

        if blog is None:
            return abort(404, "Blog not found")

        form = await request.form()

        form = PostForm(form)

        if form.validate():
            await blog.update_auto(title=form.title.data,
                                   tags=form.tags.data,
                                   content=form.content.data).apply()

            url = request.url_for("blog_view", slug=blog.slug)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "blog/edit.j2",
            {
                "request": request,
                "form": form,
                "blog": blog,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
Example #13
0
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = PostForm(form)

        is_valid = form.validate()

        if (await Blog.query.where(Blog.title == form.title.data).gino.first()
                is not None):
            is_valid = False
            form.title.errors.append(
                f"A blog with the title '{form.title.data}' already exists.")

        if is_valid:
            blog = await Blog.create_auto(title=form.title.data,
                                          tags=form.tags.data,
                                          content=form.content.data)

            url = request.url_for("blog_view", slug=blog.slug)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "blog/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
    async def __call__(self, scope: Scope, receive: Receive,
                       send: Send) -> None:
        if scope['type'] not in ('http', 'websocket'):
            await self.app(scope, receive, send)
            return

        connection = HTTPConnection(scope)

        if self.session_header in connection.headers:
            data = connection.headers[self.session_header].encode('utf-8')
            try:
                data = self.signer.unsign(data, max_age=self.max_age)
                scope['session'] = json.loads(base64.b64decode(data))
            except BadData:
                scope['session'] = {}
        else:
            scope['session'] = {}

        async def send_wrapper(message: Message) -> None:
            if message['type'] == 'http.response.start':
                if scope['session']:
                    _data = base64.b64encode(
                        json.dumps(scope['session']).encode('utf-8'))
                    _data = self.signer.sign(_data)
                    headers = MutableHeaders(scope=message)
                    headers.append('session', _data.decode('utf-8'))
            await send(message)

        await self.app(scope, receive, send_wrapper)
Example #15
0
async def index(request: HTTPConnection):
    posts = request.session.get("posts")
    if posts is None:
        posts = []
        request.session["posts"] = posts

    form = PostForm()

    return templates.TemplateResponse(
        "main.j2",
        {
            "request": request,
            "form": form,
            "posts": posts,
            "post_create": request.url_for("post"),
        },
    )
Example #16
0
 def setup_method(self):
     self.mock_request = HTTPConnection({
         'type': 'http',
         'client': ('127.0.0.1', '8000'),
     })
     self.endpoint = StatusEndpoint(scope=self.mock_request,
                                    receive=None,
                                    send=None)
Example #17
0
async def bank_login(request: HTTPConnection):
    form = await request.form()
    form = LoginForm(form)

    r = redirect_response(url=request.url_for("bank"))
    r.set_cookie("username", form.user.data)

    return r
Example #18
0
 async def __call__(self, scope: Scope, receive: Receive,
                    send: Send) -> None:
     if scope["type"] in ("http", "websocket"):
         connection = HTTPConnection(scope)
         if "user" in connection.cookies:
             user_auth = connection.cookies["user"]
             headers = MutableHeaders(scope=scope)
             headers.setdefault("Authorization", user_auth)
     await self.app(scope, receive, send)
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = ChallengeForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title.")

        if (await Challenge.query.where(
                sa.or_(
                    Challenge.title == form.title.data,
                    Challenge.slug == slug(form.title.data),
                )).gino.first() is not None):
            is_valid = False
            form.title.errors.append(
                f"A challenge with the title conflicting with '{form.title.data}' already exists."
            )

        if is_valid:
            f_a = form.flag_or_answer.data
            flag, answer = (f_a, None) if form.is_flag.data else (None, f_a)

            challenge = await Challenge.create_auto(
                title=form.title.data,
                content=form.content.data,
                flag=flag,
                answer=answer,
                hidden=form.hidden.data,
                depreciated=form.depreciated.data,
                points=form.points.data,
                tags=form.tags.data,
            )

            url = request.url_for("challenge_view", slug=challenge.slug)

            if not challenge.hidden:
                await log_create("challenge", challenge.title,
                                 request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(include_hidden=True))

        return templates.TemplateResponse(
            "challenge/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
Example #20
0
async def encoded_existing_images(request: HTTPConnection) -> bytes:
    images = await get_existing_images(request.user.discord_id)
    images = [
        {
            "filename": f"{id}.{ext}",
            "path": request.url_for("images", file_name=(id, ext)),
        }
        for (id, ext) in images
    ]
    return orjson.dumps(images)
Example #21
0
    async def post(self, request: HTTPConnection):
        id = request.path_params["id"]

        blog = await Blog.get(id)

        if blog is None:
            return abort(404, "Blog not found")

        if not can_edit(request, blog.author_id):
            return abort(400)

        form = await request.form()

        form = PostForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title.")

        if blog.title != blog.title.data:
            if (await Blog.query.where(
                    sa.or_(Blog.title == form.title.data,
                           Blog.slug == slug(form.title.data))).gino.first()
                    is not None):
                is_valid = False
                form.title.errors.append(
                    f"A blog with the title '{form.title.data}' already exists."
                )

        if is_valid:
            await blog.update_auto(title=form.title.data,
                                   tags=form.tags.data,
                                   content=form.content.data).apply()

            url = request.url_for("blog_view", slug=blog.slug)
            await log_edit("blog", blog.title, request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "blog/edit.j2",
            {
                "request": request,
                "form": form,
                "blog": blog,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
Example #22
0
async def blog_delete(request: HTTPConnection):
    id = request.path_params["id"]

    blog = await Blog.get(id)

    if blog is None:
        return abort(404, "Blog not found")

    await blog.delete()

    return redirect_response(url=request.url_for("blog_index"))
Example #23
0
 def __init__(self, scope, receive, send, request_context=None):
     assert scope["type"] == "websocket"
     self._receive = receive
     self._send = send
     self.client_state = WebSocketState.CONNECTING
     self.application_state = WebSocketState.CONNECTING
     self.scope = scope
     self.request = HTTPConnection(scope)
     super().__init__(ws=self, request_context=request_context)
     self.on_close = None
     self.on_stop = None
Example #24
0
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = WriteupForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title."
            )

        if (
            await Writeup.query.where(
                sa.or_(
                    Writeup.title == form.title.data,
                    Writeup.slug == slug(form.title.data),
                )
            ).gino.first()
            is not None
        ):
            is_valid = False
            form.title.errors.append(
                f"A writeup with the title conflicting with '{form.title.data}' already exists."
            )

        if is_valid:
            writeup = await Writeup.create_auto(
                author_id=request.user.discord_id,
                title=form.title.data,
                tags=form.tags.data,
                content=form.content.data,
                private=form.private.data,
            )

            url = request.url_for("writeups_view", slug=writeup.slug)
            await log_create("writeup", writeup.title, request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(True))

        return templates.TemplateResponse(
            "writeups/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
Example #25
0
async def auth_cb(request: HTTPConnection):
    token = await oauth.discord.authorize_access_token(request)
    resp = await oauth.discord.get(DISCORD_API_BASE + "/users/@me", token=token)
    user = resp.json()
    log.info(
        "User %s#%s (%s) completed oauth",
        user["username"],
        user["discriminator"],
        user["id"],
    )
    request.session["discord_id"] = int(user["id"])
    return RedirectResponse(url="/")
Example #26
0
async def bank_transfer(request: HTTPConnection):
    form = TransferForm(request.query_params)

    if not form.validate():
        login_form = LoginForm()

        current_user = request.cookies.get("username")

        return templates.TemplateResponse(
            "bank.j2",
            {
                "request":
                request,
                "login_form":
                login_form,
                "transfer_form":
                form,
                "login_url":
                request.url_for("bank_login"),
                "transfer_url":
                request.url_for("bank_transfer"),
                "current_user":
                current_user,
                "transactions":
                [] if current_user is None else transactions[current_user],
            },
        )

    from_ = request.cookies.get("username")
    if from_ is None:
        raise HTTPException(status_code=401, detail="Not logged in")

    transaction = (from_, form.dest.data, form.amount.data)

    print(transaction)

    transactions[form.dest.data].append(transaction)
    transactions[from_].append(transaction)

    return redirect_response(url=request.url_for("bank"))
Example #27
0
    async def __call__(self, scope: Scope, receive: Receive,
                       send: Send) -> None:
        if scope["type"] not in ("http", "websocket"):  # pragma: no cover
            await self.app(scope, receive, send)
            return

        connection = HTTPConnection(scope)
        initial_session_was_empty = True

        if self.session_cookie in connection.cookies:
            data = connection.cookies[self.session_cookie].encode("utf-8")
            try:
                data = self.signer.unsign(data, max_age=self.max_age)
                scope["session"] = json.loads(b64decode(data))
                initial_session_was_empty = False
            except BadSignature:
                scope["session"] = {}
        else:
            scope["session"] = {}

        async def send_wrapper(message: Message) -> None:
            if message["type"] == "http.response.start":
                if scope["session"]:
                    # We have session data to persist.
                    data = b64encode(
                        json.dumps(scope["session"]).encode("utf-8"))
                    data = self.signer.sign(data)
                    headers = MutableHeaders(scope=message)
                    header_value = "{session_cookie}={data}; path={path}; {max_age}{security_flags}".format(  # noqa E501
                        session_cookie=self.session_cookie,
                        data=data.decode("utf-8"),
                        path=self.path,
                        max_age=f"Max-Age={self.max_age}; "
                        if self.max_age else "",
                        security_flags=self.security_flags,
                    )
                    headers.append("Set-Cookie", header_value)
                elif not initial_session_was_empty:
                    # The session has been cleared.
                    headers = MutableHeaders(scope=message)
                    header_value = "{session_cookie}={data}; path={path}; {expires}{security_flags}".format(  # noqa E501
                        session_cookie=self.session_cookie,
                        data="null",
                        path=self.path,
                        expires="expires=Thu, 01 Jan 1970 00:00:00 GMT; ",
                        security_flags=self.security_flags,
                    )
                    headers.append("Set-Cookie", header_value)
            await send(message)

        await self.app(scope, receive, send_wrapper)
Example #28
0
async def post(request: HTTPConnection):
    form = await request.form()
    form = PostForm(form)

    name = form.name.data
    message = form.message.data

    posts = request.session.get("posts")
    if posts is None:
        posts = []
        request.session["posts"] = posts

    posts.append((name, message))

    return templates.TemplateResponse(
        "main.j2",
        {
            "request": request,
            "form": form,
            "posts": posts,
            "post_create": request.url_for("post"),
        },
    )
Example #29
0
    async def __call__(self, scope: Scope, receive: Receive,
                       send: Send) -> None:
        if scope["type"] not in ("http", "websocket"):  # pragma: no cover
            await self.app(scope, receive, send)
            return

        connection = HTTPConnection(scope)
        initial_session_was_empty = True

        if self.session_cookie in connection.cookies:
            data = connection.cookies[self.session_cookie].encode("utf-8")
            try:
                data = self.signer.unsign(data, max_age=self.max_age)
                scope["session"] = json.loads(b64decode(data))
                initial_session_was_empty = False
            except (BadTimeSignature, SignatureExpired):
                scope["session"] = {}
        else:
            scope["session"] = {}

        async def send_wrapper(message: Message) -> None:
            if message["type"] == "http.response.start":
                path = scope.get("root_path", "") or "/"
                if scope["session"]:
                    # We have session data to persist.
                    data = b64encode(
                        json.dumps(scope["session"]).encode("utf-8"))
                    data = self.signer.sign(data)
                    headers = MutableHeaders(scope=message)
                    header_value = "%s=%s; path=%s; Max-Age=%d; %s" % (
                        self.session_cookie,
                        data.decode("utf-8"),
                        path,
                        self.max_age,
                        self.security_flags,
                    )
                    headers.append("Set-Cookie", header_value)
                elif not initial_session_was_empty:
                    # The session has been cleared.
                    headers = MutableHeaders(scope=message)
                    header_value = "{}={}; {}".format(
                        self.session_cookie,
                        f"null; path={path}; expires=Thu, 01 Jan 1970 00:00:00 GMT;",
                        self.security_flags,
                    )
                    headers.append("Set-Cookie", header_value)
            await send(message)

        await self.app(scope, receive, send_wrapper)
async def challenge_delete(request: HTTPConnection):
    id = request.path_params["id"]

    challenge = await Challenge.get(id)

    if challenge is None:
        return abort(404, "Challenge not found")

    if not can_edit(request):
        return abort(400)

    await challenge.delete()
    await log_delete("challenge", challenge.title, request.user.username)

    return redirect_response(url=request.url_for("challenge_index"))