Skip to content

Commit

Permalink
server: add customer session and user session to GitHub Secret Scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
frankie567 committed Jan 2, 2025
1 parent cc6bbdb commit 5e9ac96
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 6 deletions.
48 changes: 42 additions & 6 deletions server/polar/auth/service.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
from datetime import datetime
from typing import TypeVar

import structlog
from fastapi import Request, Response
from fastapi.responses import RedirectResponse
from sqlalchemy import delete, select

from polar.config import settings
from polar.enums import TokenType
from polar.kit.crypto import generate_token_hash_pair, get_token_hash
from polar.kit.http import get_safe_return_url
from polar.kit.utils import utc_now
from polar.logging import Logger
from polar.models import User, UserSession
from polar.postgres import AsyncSession

log: Logger = structlog.get_logger()

USER_SESSION_TOKEN_PREFIX = "polar_us_"

R = TypeVar("R", bound=Response)
Expand Down Expand Up @@ -55,12 +60,7 @@ async def authenticate(
if token is None:
return None

token_hash = get_token_hash(token, secret=settings.SECRET)
statement = select(UserSession).where(
UserSession.token == token_hash, UserSession.expires_at > utc_now()
)
result = await session.execute(statement)
user_session = result.unique().scalar_one_or_none()
user_session = await self._get_user_session_by_token(session, token)

if user_session is None:
return None
Expand All @@ -71,6 +71,42 @@ async def delete_expired(self, session: AsyncSession) -> None:
statement = delete(UserSession).where(UserSession.expires_at < utc_now())
await session.execute(statement)

async def revoke_leaked(
self,
session: AsyncSession,
token: str,
token_type: TokenType,
*,
notifier: str,
url: str | None,
) -> bool:
user_session = await self._get_user_session_by_token(session, token)

if user_session is None:
return False

await session.delete(user_session)

log.info(
"Revoke leaked user session token",
id=user_session.id,
notifier=notifier,
url=url,
)

return True

async def _get_user_session_by_token(
self, session: AsyncSession, token: str, *, expired: bool = False
) -> UserSession | None:
token_hash = get_token_hash(token, secret=settings.SECRET)
statement = select(UserSession).where(UserSession.token == token_hash)
result = await session.execute(statement)
if not expired:
statement = statement.where(UserSession.expires_at > utc_now())
result = await session.execute(statement)
return result.unique().scalar_one_or_none()

async def _create_user_session(
self, session: AsyncSession, user: User, *, user_agent: str
) -> tuple[str, UserSession]:
Expand Down
30 changes: 30 additions & 0 deletions server/polar/customer_session/service.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import structlog
from sqlalchemy import delete, select
from sqlalchemy.orm import joinedload

from polar.auth.models import AuthSubject, Organization, User
from polar.config import settings
from polar.customer.service import customer as customer_service
from polar.enums import TokenType
from polar.exceptions import PolarRequestValidationError
from polar.kit.crypto import generate_token_hash_pair, get_token_hash
from polar.kit.services import ResourceServiceReader
from polar.kit.utils import utc_now
from polar.logging import Logger
from polar.models import Customer, CustomerSession
from polar.postgres import AsyncSession

from .schemas import CustomerSessionCreate

log: Logger = structlog.get_logger()

CUSTOMER_SESSION_TOKEN_PREFIX = "polar_cst_"


Expand Down Expand Up @@ -77,5 +82,30 @@ async def delete_expired(self, session: AsyncSession) -> None:
)
await session.execute(statement)

async def revoke_leaked(
self,
session: AsyncSession,
token: str,
token_type: TokenType,
*,
notifier: str,
url: str | None,
) -> bool:
customer_session = await self.get_by_token(session, token)

if customer_session is None:
return False

await session.delete(customer_session)

log.info(
"Revoke leaked customer session token",
id=customer_session.id,
notifier=notifier,
url=url,
)

return True


customer_session = CustomerSessionService(CustomerSession)
2 changes: 2 additions & 0 deletions server/polar/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ class TokenType(StrEnum):
access_token = "polar_access_token"
refresh_token = "polar_refresh_token"
personal_access_token = "polar_personal_access_token"
customer_session_token = "polar_customer_session_token"
user_session_token = "polar_user_session_token"
4 changes: 4 additions & 0 deletions server/polar/integrations/github/service/secret_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from fastapi.exceptions import RequestValidationError
from pydantic import BeforeValidator, TypeAdapter, ValidationError

from polar.auth.service import auth as auth_service
from polar.customer_session.service import customer_session as customer_session_service
from polar.enums import TokenType
from polar.exceptions import PolarError
from polar.kit.schemas import Schema
Expand Down Expand Up @@ -76,6 +78,8 @@ async def revoke_leaked(
TokenType.access_token: oauth2_token_service,
TokenType.refresh_token: oauth2_token_service,
TokenType.personal_access_token: personal_access_token_service,
TokenType.customer_session_token: customer_session_service,
TokenType.user_session_token: auth_service,
}


Expand Down

0 comments on commit 5e9ac96

Please sign in to comment.