Skip to content

Commit

Permalink
added colum level encryption on db models
Browse files Browse the repository at this point in the history
  • Loading branch information
joeygrable94 committed Apr 23, 2024
1 parent bf24230 commit 5fd46c6
Show file tree
Hide file tree
Showing 46 changed files with 1,398 additions and 642 deletions.
662 changes: 662 additions & 0 deletions alembic/versions/eea0802b7269_initial_encrypted_db.py

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions app/api/middleware/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware

from app.api.deps import get_request_client_ip
from app.api.deps.get_auth import get_current_user
from app.core import logger
from app.core.config import settings


Expand All @@ -31,6 +34,13 @@ async def add_process_time_header(request: Request, call_next: Any) -> Any:
response_result.headers["X-Process-Time"] = str(process_time)
return response_result

# @app.middleware("http")
# async def log_ip_activity(request: Request, call_next: Any) -> Any:
# """Adds a header to each response with the time it took to process."""
# req_ip = get_request_client_ip(request)
# response_result: Any = await call_next(request)
# return response_result


__all__: List[str] = [
"configure_middleware",
Expand Down
22 changes: 11 additions & 11 deletions app/api/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@
from app.api.exceptions.exceptions import WebsiteNotExists, WebsitePageNotExists
from app.core.config import settings
from app.core.logger import logger
from app.core.utilities import parse_id
from app.core.utilities.websites import fetch_url_status_code
from app.crud import WebsitePageRepository
from app.crud.website import WebsiteRepository
from app.crud.website_map import WebsiteMapRepository
from app.crud.website_pagespeedinsights import WebsitePageSpeedInsightsRepository
from app.core.utilities import fetch_url_status_code, parse_id
from app.crud import (
WebsiteMapRepository,
WebsitePageRepository,
WebsitePageSpeedInsightsRepository,
WebsiteRepository,
)
from app.db.session import get_db_session
from app.models import WebsitePage
from app.models.website import Website
from app.models.website_map import WebsiteMap
from app.models import Website, WebsiteMap, WebsitePage
from app.schemas import (
PageSpeedInsightsDevice,
WebsiteMapCreate,
WebsiteMapPage,
WebsiteMapUpdate,
WebsitePageCreate,
WebsitePageSpeedInsightsBase,
WebsitePageSpeedInsightsCreate,
WebsitePageUpdate,
)
from app.schemas.website_map import WebsiteMapCreate, WebsiteMapUpdate
from app.schemas.website_pagespeedinsights import WebsitePageSpeedInsightsCreate


async def create_or_update_website_map(
Expand Down
2 changes: 1 addition & 1 deletion app/api/v1/endpoints/web_keywordcorpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ async def website_page_keyword_corpus_create(
logger.info(
"Created Website Keyword Corpus:",
kwc_in_db.id,
kwc_in_db.created_on,
kwc_in_db.created,
)
return WebsiteKeywordCorpusRead.model_validate(kwc_in_db)

Expand Down
2 changes: 1 addition & 1 deletion app/api/v1/endpoints/web_pagespeedinsights.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async def website_page_speed_insights_create(
logger.info(
"Created Website Page Speed Insights:",
psi_in_db.id,
psi_in_db.created_on,
psi_in_db.created,
)
return WebsitePageSpeedInsightsRead.model_validate(psi_in_db)

Expand Down
4 changes: 2 additions & 2 deletions app/core/security/auth/auth0.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ class Auth0User(BaseModel):
is_verified: Optional[bool] = Field( # type: ignore [literal-required]
None, alias=f"{auth0_rule_namespace}/is_verified"
)
created_on: Optional[datetime] = Field( # type: ignore [literal-required]
created: Optional[datetime] = Field( # type: ignore [literal-required]
None, alias=f"{auth0_rule_namespace}/created_on"
)
updated_on: Optional[datetime] = Field( # type: ignore [literal-required]
updated: Optional[datetime] = Field( # type: ignore [literal-required]
None, alias=f"{auth0_rule_namespace}/updated_on"
)

Expand Down
4 changes: 2 additions & 2 deletions app/core/security/encryption/cipher_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, pass_key: str, salt: str) -> None:

def _serialize_value(self, value: bool | str | int) -> bytes:
if isinstance(value, bool):
return b"true" if value else b"false"
return b"1" if value else b"0"
elif isinstance(value, str):
return value.encode("utf-8")
elif isinstance(value, int):
Expand All @@ -38,7 +38,7 @@ def _deserialize_value(
self, serialized_value: bytes, data_type: type[bool] | type[str] | type[int]
) -> object:
if data_type == bool:
return serialized_value == b"true"
return serialized_value == b"1"
elif data_type == str:
return serialized_value.decode("utf-8")
elif data_type == int:
Expand Down
4 changes: 2 additions & 2 deletions app/crud/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async def add_privileges(
updated_scopes = entry.scopes
if schema.scopes:
updated_scopes.extend(schema.scopes)
setattr(entry, "scopes", list(set(updated_scopes)))
entry.scopes = list(set(updated_scopes))
await self._db.commit()
await self._db.refresh(entry)
return entry
Expand All @@ -120,7 +120,7 @@ async def remove_privileges(
updated_scopes = [
scope for scope in user_scopes if scope not in schema.scopes
]
setattr(entry, "scopes", list(set(updated_scopes)))
entry.scopes = list(set(updated_scopes))
await self._db.commit()
await self._db.refresh(entry)
return entry
54 changes: 34 additions & 20 deletions app/models/bdx_feed.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, List

from pydantic import UUID4
from sqlalchemy import DateTime, ForeignKey, String, func
from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy_utils import UUIDType # type: ignore
from sqlalchemy_utils import Timestamp # type: ignore
from sqlalchemy_utils import UUIDType
from sqlalchemy_utils.types.encrypted.encrypted_type import ( # type: ignore # noqa: E501
AesEngine,
StringEncryptedType,
)

from app.core.config import settings
from app.core.utilities.uuids import get_uuid # type: ignore
from app.db.base_class import Base
from app.db.constants import DB_STR_TINYTEXT_MAXLEN_STORED
Expand All @@ -15,39 +20,48 @@
from .file_asset import FileAsset # noqa: F401


class BdxFeed(Base):
class BdxFeed(Base, Timestamp):
__tablename__: str = "bdx_feed"
__table_args__: Any = {"mysql_engine": "InnoDB"}
__mapper_args__: Any = {"always_refresh": True}
id: Mapped[UUID4] = mapped_column(
UUIDType(binary=False),
index=True,
unique=True,
primary_key=True,
nullable=False,
default=get_uuid(),
)
created_on: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
default=func.current_timestamp(),
)
updated_on: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
default=func.current_timestamp(),
onupdate=func.current_timestamp(),
)
username: Mapped[str] = mapped_column(
String(DB_STR_TINYTEXT_MAXLEN_STORED),
nullable=False,
StringEncryptedType(
String,
settings.api.encryption_key,
AesEngine,
"pkcs5",
length=DB_STR_TINYTEXT_MAXLEN_STORED,
),
unique=True,
primary_key=True,
nullable=False,
)
password: Mapped[str] = mapped_column(
String(DB_STR_TINYTEXT_MAXLEN_STORED), nullable=False
StringEncryptedType(
String,
settings.api.encryption_key,
AesEngine,
"pkcs5",
length=DB_STR_TINYTEXT_MAXLEN_STORED,
),
nullable=False,
)
serverhost: Mapped[str] = mapped_column(
String(DB_STR_TINYTEXT_MAXLEN_STORED), nullable=False
StringEncryptedType(
String,
settings.api.encryption_key,
AesEngine,
"pkcs5",
length=DB_STR_TINYTEXT_MAXLEN_STORED,
),
nullable=False,
)

# relationships
Expand Down
67 changes: 44 additions & 23 deletions app/models/client.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, List, Tuple

from pydantic import UUID4
from sqlalchemy import Boolean, DateTime, String, Text, func
from sqlalchemy import Boolean, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy_utils import UUIDType # type: ignore
from sqlalchemy_utils import Timestamp # type: ignore
from sqlalchemy_utils import UUIDType
from sqlalchemy_utils.types.encrypted.encrypted_type import ( # type: ignore # noqa: E501
AesEngine,
StringEncryptedType,
)

from app.core.config import settings
from app.core.security.permissions import (
AccessCreate,
AccessDelete,
Expand All @@ -27,7 +32,11 @@
)
from app.core.utilities.uuids import get_uuid # type: ignore
from app.db.base_class import Base
from app.db.constants import DB_STR_DESC_MAXLEN_STORED, DB_STR_TINYTEXT_MAXLEN_STORED
from app.db.constants import (
DB_STR_32BIT_MAXLEN_STORED,
DB_STR_DESC_MAXLEN_STORED,
DB_STR_TINYTEXT_MAXLEN_STORED,
)

if TYPE_CHECKING: # pragma: no cover
from .bdx_feed import BdxFeed # noqa: F401
Expand All @@ -43,42 +52,54 @@
from .website import Website # noqa: F401


class Client(Base):
class Client(Base, Timestamp):
__tablename__: str = "client"
__table_args__: Any = {"mysql_engine": "InnoDB"}
__mapper_args__: Any = {"always_refresh": True}
id: Mapped[UUID4] = mapped_column(
UUIDType(binary=False),
index=True,
unique=True,
primary_key=True,
nullable=False,
default=get_uuid(),
)
created_on: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
default=func.current_timestamp(),
)
updated_on: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
default=func.current_timestamp(),
onupdate=func.current_timestamp(),
)
title: Mapped[str] = mapped_column(
String(DB_STR_TINYTEXT_MAXLEN_STORED),
nullable=False,
StringEncryptedType(
String,
settings.api.encryption_key,
AesEngine,
"pkcs5",
length=DB_STR_TINYTEXT_MAXLEN_STORED,
),
unique=True,
primary_key=True,
nullable=False,
)
description: Mapped[str] = mapped_column(
Text(DB_STR_DESC_MAXLEN_STORED), nullable=True
StringEncryptedType(
String,
settings.api.encryption_key,
AesEngine,
"pkcs5",
length=DB_STR_DESC_MAXLEN_STORED,
),
nullable=True,
)
is_active: Mapped[bool] = mapped_column(
StringEncryptedType(
Boolean,
settings.api.encryption_key,
AesEngine,
"zeroes",
length=DB_STR_32BIT_MAXLEN_STORED,
),
nullable=False,
default=True,
)
is_active: Mapped[bool] = mapped_column(Boolean(), nullable=False, default=True)

# relationships
users: Mapped[List["User"]] = relationship(
"User", secondary="user_client", back_populates="clients", lazy="selectin"
"User", secondary="user_client", back_populates="clients"
)
websites: Mapped[List["Website"]] = relationship(
secondary="client_website", back_populates="clients", cascade="all, delete"
Expand Down Expand Up @@ -142,5 +163,5 @@ def __acl__(

# representation
def __repr__(self) -> str: # pragma: no cover
repr_str: str = f"Client({self.title}, since {self.created_on})"
repr_str: str = f"Client({self.title}, since {self.created})"
return repr_str
Loading

0 comments on commit 5fd46c6

Please sign in to comment.