Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion apps/api/src/seskit_api/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from seskit_core.security.sessions import SessionData, read_session
from seskit_core.services import (
InboundProvisionerFactory,
InboundStoreFactory,
ProviderFactory,
ProvisionerFactory,
get_default_project,
Expand All @@ -33,7 +34,12 @@
touch_last_used,
verify_api_key,
)
from seskit_provider_aws_ses import SESEventProvisioner, SESInboundProvisioner, SESProvider
from seskit_provider_aws_ses import (
S3InboundStore,
SESEventProvisioner,
SESInboundProvisioner,
SESProvider,
)
from sqlalchemy.ext.asyncio import AsyncSession


Expand Down Expand Up @@ -113,6 +119,16 @@ def get_inbound_provisioner_factory() -> InboundProvisionerFactory:
return SESInboundProvisioner


def get_inbound_store_factory() -> InboundStoreFactory:
"""How a route reads a stored message back out of its bucket.

Separate from the provisioner because reading mail and building the plumbing
for it are different capabilities with different permissions - a key that
can fetch an object does not need to be able to create a bucket.
"""
return S3InboundStore


async def get_optional_user(
request: Request,
db: Annotated[AsyncSession, Depends(get_session)],
Expand Down
8 changes: 7 additions & 1 deletion apps/api/src/seskit_api/middleware/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ async def dispatch(

response = await call_next(request)

response.headers["Content-Security-Policy"] = policy_for(nonce)
# A route that set its own policy keeps it. This is the dashboard's
# policy, written for pages that render here; applying it over a route
# that deliberately set a stricter one - a download of somebody else's
# file, which sets `sandbox` - would silently discard the stricter one
# and ship the looser, with nothing to say so.
if "Content-Security-Policy" not in response.headers:
response.headers["Content-Security-Policy"] = policy_for(nonce)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
# same-origin rather than no-referrer: an unsubscribe token or an email
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/seskit_api/routes/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@

from fastapi import APIRouter

from seskit_api.routes.v1 import api_keys, domains, emails, events, webhooks
from seskit_api.routes.v1 import api_keys, domains, emails, events, inbound, webhooks

router = APIRouter(prefix="/v1")
router.include_router(api_keys.router)
router.include_router(domains.router)
router.include_router(emails.router)
router.include_router(events.router)
router.include_router(inbound.router)
router.include_router(webhooks.router)

__all__ = ["router"]
Loading
Loading