Exemple #1
0
def get_botx_wsgi_api(
    messages: List[APIMessage],
    requests: List[APIRequest],
    errors: Dict[Type[BotXMethod], Tuple[int, Any]],
) -> App:
    """Generate BotX API mock.

    Arguments:
        messages: list of message that were sent from bot and should be extended.
        requests: all requests that were sent from bot.
        errors: errors to be generated by mocked API.

    Returns:
        Generated BotX API mock for using with httpx.
    """
    return App(
        components=[
            SettingsComponent(
                Settings(messages=messages, requests=requests,
                         errors=errors), ),
        ],
        routes=list(_create_molten_routes()),
        middleware=[error_middleware],
        parsers=[JSONParser()],
    )
Exemple #2
0
def test_middleware_white_listing(app_settings, testing_token):
    def test_handler(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "No user token present"
        return jwt_identity.id

    routes = [Route("/whitelisted", method="GET", handler=test_handler)]

    components = [
        SettingsComponent({
            **app_settings, "JWT_AUTH_WHITELIST": ["test_handler"]
        }),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/whitelisted",
                          headers={"Authorization": f"Bearer {testing_token}"})

    unauthenticated = client.get("/whitelisted")
    assert 200 == response.status_code
    assert "1234567890" in response.data
    assert 200 == unauthenticated.status_code
    assert "No user token present" in unauthenticated.data
Exemple #3
0
def test_middleware_token_validation_raises_error_on_token_exp(app_settings):
    def test_handler(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "No user token present"
        return jwt_identity.id

    jwt = JWT(key="keepthissafe", alg="HS256")
    iat = dt.datetime.now() + dt.timedelta(seconds=-10)
    exp = iat + dt.timedelta(seconds=5)
    payload = {"sub": "1234567890", "name": "John Doe", "iat": iat, "exp": exp}
    token = jwt.encode(payload)

    routes = [Route("/auth-required", method="GET", handler=test_handler)]

    components = [
        SettingsComponent(app_settings),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/auth-required",
                          headers={"Authorization": f"Bearer {token}"})
    assert 401 == response.status_code
    content = response.json()
    assert "error_message" in content
    assert content.get("status") == 401
Exemple #4
0
def setup_app():
    setup_logging()

    cookie_store = CookieStore(**settings.strict_get("sessions"))

    get_schema = OpenAPIHandler(
        Metadata(
            title="Chat",
            description="A simple chat app.",
            version="0.0.0",
        ), )

    get_docs = OpenAPIUIHandler()

    app = App(
        components=[
            AccountManagerComponent(),
            ChatHandlerFactoryComponent(),
            ChatroomListenerComponent(),
            ChatroomRegistryComponent(),
            CurrentAccountComponent(),
            PasswordHasherComponent(),
            RedisComponent(),
            SQLAlchemyEngineComponent(),
            SQLAlchemySessionComponent(),
            SessionComponent(cookie_store),
            SettingsComponent(settings),
            TemplatesComponent(path_to("templates")),
        ],
        middleware=[
            RequestIdMiddleware(),
            SessionMiddleware(cookie_store),
            ResponseRendererMiddleware(),
            WebsocketsMiddleware(),
            SQLAlchemyMiddleware(),
        ],
        routes=[
            Route("/_schema", get_schema),
            Route("/_docs", get_docs),
            Route("/", index),
            Route("/login", login),
            Route("/register", register),
            Include("/v1", [
                Include("/accounts", accounts.routes, namespace="accounts"),
                Include("/chat", chat.routes, namespace="chat"),
                Include("/sessions", sessions.routes, namespace="sessions"),
            ],
                    namespace="v1"),
        ],
    )

    decorated_app = WhiteNoise(app, **settings.strict_get("whitenoise"))
    return decorated_app, app
Exemple #5
0
def test_app():
    settings = Settings({
        'database_engine_dsn': 'sqlite://',
        'identity_server': 'http://localhost',
        'secret_key': 'fake_secret',
    })
    app = create_app(
        settings=settings,
        components=[
            SettingsComponent(settings),
            SQLAlchemyEngineComponent(),
            SQLAlchemySessionComponent(),
            # RequestSessionComponent(),
            MockProvider(AuthProviderComponent),
        ],
    )
    yield app
Exemple #6
0
def test_claims_required_attaches_values(app_settings):
    @claims_required({"admin": True})
    def test_handler():
        return "Handler called"

    routes = [Route("/claims", method="GET", handler=test_handler)]

    components = [SettingsComponent(app_settings)]

    middleware = [ResponseRendererMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/claims")
    assert 200 == response.status_code
    assert "admin" in test_handler.claims
    assert test_handler.claims.get("admin") is True
    assert "Handler called" in response.data
Exemple #7
0
def test_middleware_raises_401_error(app_settings):
    def test_handler():
        return "Handler called"

    routes = [Route("/auth-required", method="GET", handler=test_handler)]

    components = [
        SettingsComponent(app_settings),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/auth-required")
    assert 401 == response.status_code
Exemple #8
0
def test_JWT_claims_options_raises_error(app_settings, testing_token):
    def test_handler(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "No user token present"
        return jwt_identity.id

    jwt = JWT(key=app_settings.get("JWT_SECRET_KEY"), alg="HS256")
    mod_token = jwt.encode({
        **jwt.decode(testing_token),
        **{
            "iss": "https://molten.com"
        }
    })

    routes = [Route("/claim_options", method="GET", handler=test_handler)]

    components = [
        SettingsComponent({
            **app_settings,
            "JWT_CLAIMS_OPTIONS": {
                "iss": {
                    "essential": True,
                    "values": ["https://example.com", "https://example.org"],
                }
            },
        }),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    missing_claim_response = client.get(
        "/claim_options", headers={"Authorization": f"Bearer {testing_token}"})
    wrong_claim_value_response = client.get(
        "/claim_options", headers={"Authorization": f"Bearer {mod_token}"})
    assert 401 == missing_claim_response.status_code
    assert 401 == wrong_claim_value_response.status_code
Exemple #9
0
def test_claims_required_raises_error(app_settings, testing_token):
    @claims_required({"admin": True})
    def test_handler():
        return "Handler called"

    routes = [Route("/claims", method="GET", handler=test_handler)]

    components = [
        SettingsComponent(app_settings),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/claims",
                          headers={"Authorization": f"Bearer {testing_token}"})
    assert 403 == response.status_code
Exemple #10
0
def test_middleware_anonymous_user_support(app_settings):
    @allow_anonymous
    def test_handler():
        return "Handler called"

    routes = [Route("/auth-maybe", method="GET", handler=test_handler)]

    components = [
        SettingsComponent(app_settings),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/auth-maybe")
    assert 200 == response.status_code
    assert "Handler called" in response.data
Exemple #11
0
def create_app(middleware=None, components=None, settings=None):
    if settings is None:
        settings = Settings({
            'database_engine_dsn': os.environ['SQLALCHEMY_URI'],
            'identity_server': os.environ['IDENTITY_SERVER'],
            'secret_key': os.environ['SECRET_KEY'],
        })

    if middleware is None:
        middleware = [
            ResponseRendererMiddleware(),
            SQLAlchemyMiddleware(),
            auth_middleware,
        ]

    if components is None:
        components = [
            SettingsComponent(settings),
            SQLAlchemyEngineComponent(),
            SQLAlchemySessionComponent(),
            RequestSessionComponent(),
            AuthProviderComponent(),
            ManagerComponent(ChoreInstanceManager),
            ManagerComponent(ChoreDefinitionManager),
            UserProviderComponent(),
        ]

    app = App(
        routes=[
            Route('/login', login, method='POST', name='login'),
            Include(
                '/api',
                routes,
                namespace='api',
            )
        ],
        middleware=middleware,
        components=components,
    )
    return app
Exemple #12
0
def test_identity_extract_jwt_from_cookie(app_settings):
    def test_auth(jwt: JWT):
        cookie_name = "molten_auth_cookie"
        cookie_value = jwt.encode({"sub": 123456, "name": "spiderman"})
        auth_response = Response(HTTP_200)
        auth_response.set_cookie(Cookie(cookie_name, cookie_value))
        return auth_response

    def test_cookie(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "Didn't work"
        return f"Hello {jwt_identity.name} your sub id is {jwt_identity.sub}"

    routes = [
        Route("/auth", method="POST", handler=test_auth),
        Route("/cookie", method="GET", handler=test_cookie),
    ]

    components = [
        SettingsComponent({
            **app_settings,
            **{
                "JWT_AUTH_COOKIE": "molten_auth_cookie"
            }
        }),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    app = App(routes=routes, components=components)
    client = testing.TestClient(app)

    auth_response = client.post("/auth")
    cookie_value = auth_response.headers.get_all("set-cookie")[0]
    assert "molten_auth_cookie" in cookie_value
    cookie_response = client.get("/cookie", headers={"cookie": cookie_value})
    assert "123456" in cookie_response.data
    assert "spiderman" in cookie_response.data
Exemple #13
0
def test_middleware_token_validation_passes(app_settings, testing_token):
    def test_handler(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "No user token present"
        return jwt_identity.id

    routes = [Route("/auth-required", method="GET", handler=test_handler)]

    components = [
        SettingsComponent(app_settings),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()]

    app = App(routes=routes, components=components, middleware=middleware)
    client = testing.TestClient(app)

    response = client.get("/auth-required",
                          headers={"Authorization": f"Bearer {testing_token}"})
    assert 200 == response.status_code
    assert "1234567890" in response.data
Exemple #14
0
def setup_app():
    setup_logging()

    get_docs = OpenAPIUIHandler()
    get_schema = OpenAPIHandler(
        metadata=Metadata(
            title="Pets",
            description="",
            version="0.0.0",
        ),
    )

    app = App(
        components=[
            ManagerComponent(PetManager),
            SQLAlchemyEngineComponent(),
            SQLAlchemySessionComponent(),
            SettingsComponent(settings),
            TemplatesComponent(path_to("templates")),
        ],

        middleware=[
            RequestIdMiddleware(),
            ResponseRendererMiddleware(),
            SQLAlchemyMiddleware(),
        ],

        routes=[
            Route("/_docs", get_docs),
            Route("/_schema", get_schema),
            Route("/", index),
            Include("/v1/pets", pets.routes, namespace="pets"),
        ],
    )

    decorated_app = WhiteNoise(app, **settings.strict_get("whitenoise"))
    return decorated_app, app
Exemple #15
0
def test_missing_auth_cookie(app_settings):
    def test_cookie(jwt_identity: JWTIdentity):
        if jwt_identity is None:
            return "Didn't work"
        return f"Hello {jwt_identity.name} your sub id is {jwt_identity.sub}"

    routes = [Route("/cookie", method="GET", handler=test_cookie)]

    components = [
        SettingsComponent({
            **app_settings,
            **{
                "JWT_AUTH_COOKIE": "molten_auth_cookie"
            }
        }),
        JWTComponent(),
        JWTIdentityComponent(),
    ]

    app = App(routes=routes, components=components)
    client = testing.TestClient(app)

    cookie_response = client.get("/cookie")
    assert "Didn't work" in cookie_response.data
Exemple #16
0
class Signup:
    email: str
    first_name: str


def send_async_email(mail: Mail, msg: Message) -> None:
    mail.send(msg)


def sign_up(signup: Signup, mail: Mail, templates: MailTemplates):
    """Handler that simulates a basic async sending of an html templated welcome email"""
    msg = Message(
        subject="Welcome to Molten!",
        body="This is a body that gets shown if html can't",
        html=templates.render("welcome_mail.html", name=signup.first_name),
        recipients=[signup.email],
    )
    Thread(target=send_async_email, args=(mail, msg)).start()
    return Response(HTTP_204, content="")


routes = [Route("/", sign_up, "POST")]

components = [
    SettingsComponent(settings),
    MailComponent(),
    MailTemplatesComponent("templates"),
]

app = App(routes=routes, components=components)
Exemple #17
0
from molten import App, Route, Settings, SettingsComponent, testing


def index(settings: Settings) -> dict:
    return settings


app = App(
    components=[SettingsComponent(Settings({"database_dsn": "sqlite://"}))],
    routes=[Route("/", index)],
)

client = testing.TestClient(app)


def test_apps_can_load_settings():
    # Given that I have an app that uses settings
    # When I make a request to that handler
    response = client.get(app.reverse_uri("index"))

    # Then I should get back a successful response
    assert response.status_code == 200
    # And the response should contain the settings
    assert response.json() == {
        "database_dsn": "sqlite://",
    }
Exemple #18
0
    metadata=Metadata(
        title="Molten-Boilerplate API",
        description="An API for Molten-Boilerplate.",
        version="0.0.0",
    ),
    security_schemes=[
        HTTPSecurityScheme("default", "bearer"),
    ],
    default_security_scheme="default",
)

components: List[Component] = [
    # TOMLSettingsComponent(),
    SQLAlchemyEngineComponent(),
    SQLAlchemySessionComponent(),
    SettingsComponent(settings.SETTINGS)
]

middleware: List[Middleware] = [
    ResponseRendererMiddleware(),
    SQLAlchemyMiddleware(),
]

routes: List[Union[Route, Include]] = [
    Include("/api/v1/users", [
        Route("", list_users),
        Route("", create_user, method="POST"),
        Route("/{user_id}", delete_user, method="DELETE"),
        Route("/{user_id}", get_user),
    ]),
Exemple #19
0
        "MAIL_PASSWORD": "******",
        "MAIL_PORT": 587,
        "MAIL_USE_TLS": True,
        "MAIL_DEFAULT_SENDER": "*****@*****.**",
    }
)


def send_message(params: QueryParams, mail: Mail):
    """Emails an email address provided in the query string"""
    addresses = params.get_all("email")
    if not addresses:
        return Response(
            HTTP_400,
            content="Provide emails in the query params to send a welcome message",
        )
    msg = Message(
        subject="Welcome to Molten!",
        body="Welcome to Molten! Glad to have you here.",
        recipients=addresses,
    )
    mail.send(msg)
    return Response(HTTP_204, content="")


routes = [Route("/", send_message, "POST")]

components = [SettingsComponent(settings), MailComponent()]

app = App(routes=routes, components=components)