From 93609e9a901e18e8b65d142656b0f83ffc9dc344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Birk=20Jernstr=C3=B6m?= Date: Tue, 14 May 2024 14:00:41 +0200 Subject: [PATCH] server: Disable authz and public page in case of blocked subject --- .../2024-05-14-1324_org_and_user_blocking.py | 38 +++++++++++++++++++ server/polar/authz/service.py | 5 +++ server/polar/models/organization.py | 7 ++++ server/polar/models/user.py | 7 ++++ server/polar/organization/schemas.py | 10 +++-- server/polar/organization/service.py | 1 + 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 server/migrations/versions/2024-05-14-1324_org_and_user_blocking.py diff --git a/server/migrations/versions/2024-05-14-1324_org_and_user_blocking.py b/server/migrations/versions/2024-05-14-1324_org_and_user_blocking.py new file mode 100644 index 0000000000..adac24a618 --- /dev/null +++ b/server/migrations/versions/2024-05-14-1324_org_and_user_blocking.py @@ -0,0 +1,38 @@ +"""org and user blocking + +Revision ID: 22b6469a1294 +Revises: 5b96b5f08ddc +Create Date: 2024-05-14 13:24:45.231403 + +""" + +import sqlalchemy as sa +from alembic import op + +# Polar Custom Imports +from polar.kit.extensions.sqlalchemy import PostgresUUID + +# revision identifiers, used by Alembic. +revision = "22b6469a1294" +down_revision = "5b96b5f08ddc" +branch_labels: tuple[str] | None = None +depends_on: tuple[str] | None = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "organizations", + sa.Column("blocked_at", sa.TIMESTAMP(timezone=True), nullable=True), + ) + op.add_column( + "users", sa.Column("blocked_at", sa.TIMESTAMP(timezone=True), nullable=True) + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("users", "blocked_at") + op.drop_column("organizations", "blocked_at") + # ### end Alembic commands ### diff --git a/server/polar/authz/service.py b/server/polar/authz/service.py index 35f62ac0fc..ecbfcd7c9d 100644 --- a/server/polar/authz/service.py +++ b/server/polar/authz/service.py @@ -67,6 +67,11 @@ async def authz(cls, session: AsyncSession = Depends(get_db_session)) -> Self: async def can( self, subject: Subject, accessType: AccessType, object: Object ) -> bool: + # Check blocked subjects + blocked_at = getattr(subject, "blocked_at", None) + if blocked_at is not None: + return False + # Anoymous users can only read if (isinstance(subject, Anonymous)) and accessType != AccessType.read: return False diff --git a/server/polar/models/organization.py b/server/polar/models/organization.py index d982a97ea2..02673e6269 100644 --- a/server/polar/models/organization.py +++ b/server/polar/models/organization.py @@ -117,6 +117,13 @@ def account(cls) -> Mapped[Account | None]: onboarded_at: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True)) + # Time of blocking traffic/activity to given organization + blocked_at: Mapped[datetime | None] = mapped_column( + TIMESTAMP(timezone=True), + nullable=True, + default=None, + ) + # If this organization was created from a GitHub User object, without installing # the Polar GitHub App. created_from_user_maintainer_upgrade: Mapped[Boolean] = mapped_column( diff --git a/server/polar/models/user.py b/server/polar/models/user.py index 29b1f7fb57..0baaf7ba91 100644 --- a/server/polar/models/user.py +++ b/server/polar/models/user.py @@ -132,6 +132,13 @@ def oauth_accounts(cls) -> Mapped[list[OAuthAccount]]: String, nullable=True, default=None, unique=True ) + # Time of blocking traffic/activity for given user + blocked_at: Mapped[datetime | None] = mapped_column( + TIMESTAMP(timezone=True), + nullable=True, + default=None, + ) + def get_oauth_account(self, platform: OAuthPlatform) -> OAuthAccount | None: return next( ( diff --git a/server/polar/organization/schemas.py b/server/polar/organization/schemas.py index c66c1a14d3..f8a64b454b 100644 --- a/server/polar/organization/schemas.py +++ b/server/polar/organization/schemas.py @@ -121,6 +121,12 @@ def from_db( o.feature_settings ) + public_page_enabled = bool( + o.installation_id or o.created_from_user_maintainer_upgrade + ) + if o.blocked_at is not None: + public_page_enabled = False + return cls( id=o.id, platform=o.platform, @@ -140,9 +146,7 @@ def from_db( account_id=o.account_id, has_app_installed=o.installation_id is not None, custom_domain=o.custom_domain, - public_page_enabled=True - if o.installation_id or o.created_from_user_maintainer_upgrade - else False, + public_page_enabled=public_page_enabled, donations_enabled=o.donations_enabled, public_donation_timestamps=o.public_donation_timestamps, profile_settings=profile_settings, diff --git a/server/polar/organization/service.py b/server/polar/organization/service.py index 6c73c28279..63d375f8f7 100644 --- a/server/polar/organization/service.py +++ b/server/polar/organization/service.py @@ -99,6 +99,7 @@ async def list_all_orgs_by_user_id( UserOrganization.user_id == user_id, UserOrganization.deleted_at.is_(None), Organization.deleted_at.is_(None), + Organization.blocked_at.is_(None), ) )