Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Db refactor #56

Merged
merged 2 commits into from
Apr 24, 2023
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
910 changes: 439 additions & 471 deletions authpage/package-lock.json

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions authpage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@
},
"dependencies": {
"@tiptenbrink/opaquewasm": "^0.3.0",
"@zxcvbn-ts/core": "^2.1.0",
"@zxcvbn-ts/core": "^2.2.1",
"@zxcvbn-ts/language-common": "^2.0.1",
"ky": "^0.33.1",
"ky": "^0.33.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite-plugin-top-level-await": "^1.2.2",
"vite-plugin-wasm": "^3.1.1",
"zod": "^3.19.1"
"vite-plugin-top-level-await": "^1.3.0",
"vite-plugin-wasm": "^3.2.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@types/node": "^18.11.9",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^2.2.0",
"sass": "^1.57.1",
"typescript": "^4.9.4",
"vite": "^3.2.5",
"@types/node": "^18.15.6",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^3.1.0",
"sass": "^1.59.3",
"typescript": "^5.0.2",
"vite": "^4.2.1",
"vite-plugin-svgr": "^2.4.0"
}
}
2 changes: 1 addition & 1 deletion src/apiserver/auth/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async def send_register_start(dsrc: Source, user_id: str, client_request: str):
auth_id = util.random_time_hash_hex(user_id)

async with data.get_conn(dsrc) as conn:
opaque_setup = await data.opaquesetup.get_setup(dsrc, conn)
opaque_setup = await data.opaquesetup.get_setup(conn)

response = opq.register(opaque_setup, client_request, user_id)
saved_state = SavedRegisterState(user_id=user_id)
Expand Down
16 changes: 7 additions & 9 deletions src/apiserver/auth/tokens_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def do_refresh(dsrc: Source, old_refresh_token: str):
try:
# See if previous refresh exists
saved_refresh = await data.refreshtoken.get_refresh_by_id(
dsrc, conn, old_refresh.id
conn, old_refresh.id
)
except DataError as e:
if e.key != "refresh_empty":
Expand All @@ -54,7 +54,7 @@ async def do_refresh(dsrc: Source, old_refresh_token: str):
# So if someone possesses some deleted token family member, it is most
# likely an attacker. For this reason, all tokens in the family are
# invalidated to prevent further compromise
await data.refreshtoken.delete_family(dsrc, conn, old_refresh.family_id)
await data.refreshtoken.delete_family(conn, old_refresh.family_id)
raise InvalidRefresh("Not recent")

verify_refresh(saved_refresh, old_refresh, utc_now)
Expand All @@ -71,9 +71,9 @@ async def do_refresh(dsrc: Source, old_refresh_token: str):
# Deletes previous token, saves new one, only succeeds if all components of the
# transaction succeed
async with data.get_conn(dsrc) as conn:
await data.refreshtoken.delete_refresh_by_id(dsrc, conn, saved_refresh.id)
await data.refreshtoken.delete_refresh_by_id(conn, saved_refresh.id)
new_refresh_id = await data.refreshtoken.insert_refresh_row(
dsrc, conn, new_refresh_save
conn, new_refresh_save
)

refresh_token, access_token, id_token = finish_tokens(
Expand All @@ -98,16 +98,14 @@ async def new_token(
utc_now = utc_timestamp()

async with data.get_conn(dsrc) as conn:
ud = await data.user.get_userdata_by_id(dsrc, conn, user_id)
ud = await data.user.get_userdata_by_id(conn, user_id)
id_info = id_info_from_ud(ud)

access_token_data, id_token_data, access_scope, refresh_save = create_tokens(
user_id, scope, auth_time, id_nonce, utc_now, id_info
)

refresh_id = await data.refreshtoken.insert_refresh_row(
dsrc, conn, refresh_save
)
refresh_id = await data.refreshtoken.insert_refresh_row(conn, refresh_save)

refresh_token, access_token, id_token = finish_tokens(
refresh_id,
Expand All @@ -133,4 +131,4 @@ async def delete_refresh(dsrc: Source, refresh_token: str):
return None

async with data.get_conn(dsrc) as conn:
await data.refreshtoken.delete_family(dsrc, conn, refresh.family_id)
await data.refreshtoken.delete_family(conn, refresh.family_id)
2 changes: 1 addition & 1 deletion src/apiserver/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from apiserver.data.source import Source, NoDataError, DataError
from apiserver.data.use import get_conn
from apiserver.data.db import get_conn
from apiserver.data import kv
from apiserver.data import user
from apiserver.data import key
Expand Down
20 changes: 20 additions & 0 deletions src/apiserver/data/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import AsyncIterator

from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine

from apiserver.data import Source, DataError


def eng_is_init(dsrc: Source):
if dsrc.gateway.db is None:
raise DataError("Database not initialized!", "no_db_init")
else:
return dsrc.gateway.db


def begin_conn(engine: AsyncEngine) -> AsyncIterator[AsyncConnection]:
return engine.begin()


def get_conn(dsrc: Source) -> AsyncIterator[AsyncConnection]:
return begin_conn(eng_is_init(dsrc))
44 changes: 22 additions & 22 deletions src/apiserver/data/key.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
from sqlalchemy.ext.asyncio import AsyncConnection

from apiserver.data.use import (
from apiserver.db.model import (
JWK_VALUE,
KEY_ID,
KEY_ISSUED,
KEY_USE,
KEY_TABLE,
JWK_TABLE,
)
from apiserver.db.db import (
retrieve_by_id,
get_largest_where,
update_column_by_unique,
insert,
)
from apiserver.define.entities import JWKSRow
from apiserver.data.source import Source, DataError
from apiserver.db import KEY_TABLE, JWK_TABLE
from apiserver.db.model import JWK_VALUE, KEY_ID, KEY_ISSUED, KEY_USE
from apiserver.data.source import DataError


MINIMUM_KEYS = 2


async def get_newest_symmetric(dsrc: Source, conn: AsyncConnection) -> tuple[str, str]:
async def get_newest_symmetric(conn: AsyncConnection) -> tuple[str, str]:
results = await get_largest_where(
dsrc, conn, KEY_TABLE, {KEY_ID}, KEY_USE, "enc", KEY_ISSUED, 2
conn, KEY_TABLE, {KEY_ID}, KEY_USE, "enc", KEY_ISSUED, 2
)
if len(results) < MINIMUM_KEYS:
raise DataError(
Expand All @@ -27,38 +33,32 @@ async def get_newest_symmetric(dsrc: Source, conn: AsyncConnection) -> tuple[str
return results[0], results[1]


async def get_newest_pem(dsrc: Source, conn: AsyncConnection) -> str:
async def get_newest_pem(conn: AsyncConnection) -> str:
return (
await get_largest_where(
dsrc, conn, KEY_TABLE, {KEY_ID}, KEY_USE, "sig", KEY_ISSUED, 1
conn, KEY_TABLE, {KEY_ID}, KEY_USE, "sig", KEY_ISSUED, 1
)
)[0]


async def insert_key(
dsrc: Source, conn: AsyncConnection, kid: str, iat: int, use: str
) -> int:
async def insert_key(conn: AsyncConnection, kid: str, iat: int, use: str) -> int:
row = {KEY_ID: kid, KEY_ISSUED: iat, KEY_USE: use}
return await insert(dsrc, conn, KEY_TABLE, row)
return await insert(conn, KEY_TABLE, row)


async def insert_jwk(
dsrc: Source, conn: AsyncConnection, encrypted_jwk_set: str
) -> int:
async def insert_jwk(conn: AsyncConnection, encrypted_jwk_set: str) -> int:
jwk_set_row = {"id": 1, JWK_VALUE: encrypted_jwk_set}
return await insert(dsrc, conn, JWK_TABLE, jwk_set_row)
return await insert(conn, JWK_TABLE, jwk_set_row)


async def update_jwk(
dsrc: Source, conn: AsyncConnection, encrypted_jwk_set: str
) -> int:
async def update_jwk(conn: AsyncConnection, encrypted_jwk_set: str) -> int:
return await update_column_by_unique(
dsrc, conn, JWK_TABLE, JWK_VALUE, encrypted_jwk_set, "id", 1
conn, JWK_TABLE, JWK_VALUE, encrypted_jwk_set, "id", 1
)


async def get_jwk(dsrc: Source, conn: AsyncConnection) -> str:
row_dict = await retrieve_by_id(dsrc, conn, JWK_TABLE, 1)
async def get_jwk(conn: AsyncConnection) -> str:
row_dict = await retrieve_by_id(conn, JWK_TABLE, 1)
if row_dict is None:
raise DataError(message="JWK Set missing.", key="missing_jwks")
return JWKSRow.parse_obj(row_dict).encrypted_value
26 changes: 11 additions & 15 deletions src/apiserver/data/opaquesetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@

from sqlalchemy.ext.asyncio import AsyncConnection

from apiserver.data.use import retrieve_by_id, insert
from apiserver.data.source import DataError
from apiserver.db.db import retrieve_by_id, insert
from apiserver.db.model import OPAQUE_SETUP_TABLE
from apiserver.define.entities import OpaqueSetup
from apiserver.data.source import Source, DataError
from apiserver.db import OPAQUE_SETUP_TABLE

__all__ = ["get_setup", "insert_opaque_row"]


async def _get_opaque_row(
dsrc: Source, conn: AsyncConnection, id_int: int
) -> Optional[dict]:
opaque_row = await retrieve_by_id(dsrc, conn, OPAQUE_SETUP_TABLE, id_int)
async def _get_opaque_row(conn: AsyncConnection, id_int: int) -> Optional[dict]:
opaque_row = await retrieve_by_id(conn, OPAQUE_SETUP_TABLE, id_int)

return opaque_row


async def _get_opaque_setup(dsrc: Source, conn: AsyncConnection) -> OpaqueSetup:
async def _get_opaque_setup(conn: AsyncConnection) -> OpaqueSetup:
# TODO set id in config
id_int = 0
opaque_row = await _get_opaque_row(dsrc, conn, id_int)
opaque_row = await _get_opaque_row(conn, id_int)
if opaque_row is None:
# new_setup = new_opaque_setup(0)
# await upsert_opaque_row(dsrc, new_setup.dict())
Expand All @@ -32,11 +30,9 @@ async def _get_opaque_setup(dsrc: Source, conn: AsyncConnection) -> OpaqueSetup:
return OpaqueSetup.parse_obj(opaque_row)


async def get_setup(dsrc: Source, conn: AsyncConnection) -> str:
return (await _get_opaque_setup(dsrc, conn)).value
async def get_setup(conn: AsyncConnection) -> str:
return (await _get_opaque_setup(conn)).value


async def insert_opaque_row(
dsrc: Source, conn: AsyncConnection, opaque_setup: OpaqueSetup
):
return await insert(dsrc, conn, OPAQUE_SETUP_TABLE, opaque_setup.dict())
async def insert_opaque_row(conn: AsyncConnection, opaque_setup: OpaqueSetup):
return await insert(conn, OPAQUE_SETUP_TABLE, opaque_setup.dict())
30 changes: 13 additions & 17 deletions src/apiserver/data/refreshtoken.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@

from sqlalchemy.ext.asyncio import AsyncConnection

from apiserver.data.source import DataError, Source
from apiserver.data.use import (
from apiserver.db.model import REFRESH_TOKEN_TABLE, FAMILY_ID, USER_ID
from apiserver.db.db import (
retrieve_by_id,
insert_return_col,
delete_by_column,
delete_by_id,
)
from apiserver.data.source import DataError
from apiserver.define.entities import SavedRefreshToken
from apiserver.db.model import REFRESH_TOKEN_TABLE, FAMILY_ID, USER_ID


async def insert_refresh_row(
dsrc: Source, conn: AsyncConnection, refresh: SavedRefreshToken
) -> int:
async def insert_refresh_row(conn: AsyncConnection, refresh: SavedRefreshToken) -> int:
refresh_row = refresh.dict(exclude={"id"})
return await insert_return_col(dsrc, conn, REFRESH_TOKEN_TABLE, refresh_row, "id")
return await insert_return_col(conn, REFRESH_TOKEN_TABLE, refresh_row, "id")


def parse_refresh(refresh_dict: Optional[dict]) -> SavedRefreshToken:
Expand All @@ -26,20 +24,18 @@ def parse_refresh(refresh_dict: Optional[dict]) -> SavedRefreshToken:
return SavedRefreshToken.parse_obj(refresh_dict)


async def get_refresh_by_id(
dsrc: Source, conn: AsyncConnection, id_int: int
) -> SavedRefreshToken:
refresh_row = await retrieve_by_id(dsrc, conn, REFRESH_TOKEN_TABLE, id_int)
async def get_refresh_by_id(conn: AsyncConnection, id_int: int) -> SavedRefreshToken:
refresh_row = await retrieve_by_id(conn, REFRESH_TOKEN_TABLE, id_int)
return parse_refresh(refresh_row)


async def delete_family(dsrc: Source, conn: AsyncConnection, family_id: str):
return await delete_by_column(dsrc, conn, REFRESH_TOKEN_TABLE, FAMILY_ID, family_id)
async def delete_family(conn: AsyncConnection, family_id: str):
return await delete_by_column(conn, REFRESH_TOKEN_TABLE, FAMILY_ID, family_id)


async def delete_refresh_by_id(dsrc: Source, conn: AsyncConnection, id_int: int):
return await delete_by_id(dsrc, conn, REFRESH_TOKEN_TABLE, id_int)
async def delete_refresh_by_id(conn: AsyncConnection, id_int: int):
return await delete_by_id(conn, REFRESH_TOKEN_TABLE, id_int)


async def delete_by_user_id(dsrc: Source, conn: AsyncConnection, user_id: str):
return await delete_by_column(dsrc, conn, REFRESH_TOKEN_TABLE, USER_ID, user_id)
async def delete_by_user_id(conn: AsyncConnection, user_id: str):
return await delete_by_column(conn, REFRESH_TOKEN_TABLE, USER_ID, user_id)
Loading