refactors settings and adds security tests

This commit is contained in:
msramalho
2024-10-20 21:30:00 +01:00
parent d2f9f91a5c
commit 84cbf720a9
15 changed files with 203 additions and 47 deletions

View File

@@ -37,7 +37,7 @@ jobs:
working-directory: src
- name: Run tests with coverage
run: PYTHONPATH=. pipenv run coverage run -m pytest -v --color=yes tests/
run: PYTHONPATH=. PIPENV_DOTENV_LOCATION=.env.test pipenv run coverage run -m pytest -v --color=yes tests/
working-directory: src
- name: Report coverage

View File

@@ -26,6 +26,7 @@ watchdog = "*"
pytest = "*"
httpx = "*"
coverage = "*"
pytest-asyncio = "*"
[requires]
python_version = "3.10"

65
src/Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "c34b5745f3a6f67222d3f26e6c7f2d13615a3301d0ca4d1f2b0ec58474b1d43a"
"sha256": "da25332a2152541157c6873ec43ac771c5491bff7d60bb2714c26c4e6b40577f"
},
"pipfile-spec": 6,
"requires": {
@@ -289,25 +289,26 @@
},
"boto3": {
"hashes": [
"sha256:a5b00f8b82dce62870759f04861747944da834d64a64355970120c475efdafc0",
"sha256:e1f36f8be453505cebcc3da178ea081b2a06c0e5e1cdee774f1067599b8d9c3e"
"sha256:18416d07b41e6094101a44f8b881047dcec6b846dad0b9f83b9bbf2f0cd93d07",
"sha256:7f8e8a252458d584d8cf7877c372c4f74ec103356eedf43d2dd9e479f47f3639"
],
"markers": "python_version >= '3.8'",
"version": "==1.35.42"
"version": "==1.35.44"
},
"botocore": {
"hashes": [
"sha256:05af0bb8b9cea7ce7bc589c332348d338a21b784e9d088a588fd10ec145007ff",
"sha256:af348636f73dc24b7e2dc760a34d08c8f2f94366e9b4c78d877307b128abecef"
"sha256:1fcd97b966ad8a88de4106fe1bd3bbd6d8dadabe99bbd4a6aadcf11cb6c66b39",
"sha256:55388e80624401d017a9a2b8109afd94814f7e666b53e28fce51375cfa8d9326"
],
"markers": "python_version >= '3.8'",
"version": "==1.35.42"
"version": "==1.35.44"
},
"brotli": {
"hashes": [
"sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208",
"sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48",
"sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354",
"sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419",
"sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a",
"sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128",
"sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c",
@@ -315,43 +316,67 @@
"sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9",
"sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a",
"sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3",
"sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757",
"sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2",
"sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438",
"sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578",
"sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b",
"sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b",
"sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68",
"sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0",
"sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d",
"sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943",
"sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd",
"sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409",
"sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28",
"sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da",
"sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50",
"sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f",
"sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0",
"sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547",
"sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180",
"sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0",
"sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d",
"sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a",
"sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb",
"sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112",
"sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc",
"sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2",
"sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265",
"sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327",
"sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95",
"sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec",
"sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd",
"sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c",
"sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38",
"sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914",
"sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0",
"sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a",
"sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7",
"sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368",
"sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c",
"sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0",
"sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f",
"sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451",
"sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f",
"sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8",
"sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e",
"sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248",
"sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c",
"sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91",
"sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724",
"sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7",
"sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966",
"sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9",
"sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97",
"sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d",
"sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5",
"sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf",
"sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac",
"sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b",
"sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951",
"sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74",
"sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648",
"sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60",
"sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c",
"sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1",
@@ -362,27 +387,44 @@
"sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460",
"sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751",
"sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9",
"sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2",
"sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0",
"sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1",
"sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474",
"sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75",
"sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5",
"sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f",
"sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2",
"sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f",
"sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb",
"sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6",
"sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9",
"sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111",
"sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2",
"sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01",
"sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467",
"sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619",
"sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf",
"sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408",
"sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579",
"sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84",
"sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7",
"sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c",
"sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284",
"sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52",
"sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b",
"sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59",
"sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752",
"sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1",
"sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80",
"sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839",
"sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0",
"sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2",
"sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3",
"sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64",
"sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089",
"sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643",
"sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b",
"sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e",
"sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985",
"sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596",
@@ -3401,6 +3443,15 @@
"markers": "python_version >= '3.8'",
"version": "==8.2.2"
},
"pytest-asyncio": {
"hashes": [
"sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b",
"sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==0.24.0"
},
"sniffio": {
"hashes": [
"sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",

View File

@@ -8,18 +8,16 @@ from loguru import logger
from db import crud, models
from db.database import get_db, make_engine
from shared.settings import Settings
from shared.settings import get_settings
from utils.metrics import measure_regular_metrics, redis_subscribe_worker_exceptions
settings = Settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
# see https://fastapi.tiangolo.com/advanced/events/#lifespan
# STARTUP
engine = make_engine(settings.DATABASE_PATH)
engine = make_engine(get_settings().DATABASE_PATH)
models.Base.metadata.create_all(bind=engine)
alembic.config.main(argv=['--raiseerr', 'upgrade', 'head'])
# disabling uvicorn logger since we use loguru in logging_middleware
@@ -42,6 +40,6 @@ async def refresh_user_groups():
crud.upsert_user_groups(db)
@repeat_every(seconds=settings.REPEAT_COUNT_METRICS_SECONDS)
@repeat_every(seconds=get_settings().REPEAT_COUNT_METRICS_SECONDS)
async def repeat_measure_regular_metrics():
measure_regular_metrics(settings.DATABASE_PATH, settings.REPEAT_COUNT_METRICS_SECONDS)
measure_regular_metrics(get_settings().DATABASE_PATH, get_settings().REPEAT_COUNT_METRICS_SECONDS)

View File

@@ -5,13 +5,13 @@ from loguru import logger
from datetime import datetime, timedelta
from web.security import ALLOW_ANY_EMAIL
from shared.settings import Settings
from shared.settings import get_settings
from . import models, schemas
import yaml
DOMAIN_GROUPS = {}
DOMAIN_GROUPS_LOADED = False
DATABASE_QUERY_LIMIT = Settings().DATABASE_QUERY_LIMIT
DATABASE_QUERY_LIMIT = get_settings().DATABASE_QUERY_LIMIT
# --------------- TASK = Archive
@@ -152,7 +152,7 @@ def upsert_user_groups(db: Session):
along with new participation of users in groups
"""
logger.debug("Updating user-groups configuration.")
filename = Settings().USER_GROUPS_FILENAME
filename = get_settings().USER_GROUPS_FILENAME
# read yaml safely
try:

View File

@@ -1,11 +1,9 @@
from sqlalchemy import Engine, create_engine, event
from sqlalchemy.orm import sessionmaker, declarative_base
from shared.settings import Settings
from sqlalchemy.orm import sessionmaker
from shared.settings import get_settings
from contextlib import contextmanager
settings = Settings()
def make_engine(database_url: str):
engine = create_engine(database_url, connect_args={"check_same_thread": False})
@@ -25,7 +23,7 @@ def make_session_local(engine: Engine):
@contextmanager
def get_db():
session = make_session_local(make_engine(settings.DATABASE_PATH))()
session = make_session_local(make_engine(get_settings().DATABASE_PATH))()
try: yield session
finally: session.close()

View File

@@ -5,12 +5,12 @@ from sqlalchemy import pool
from alembic import context
from shared.settings import Settings
from shared.settings import get_settings
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
config.set_main_option('sqlalchemy.url', Settings().DATABASE_PATH)
config.set_main_option('sqlalchemy.url', get_settings().DATABASE_PATH)
# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:

View File

@@ -1,4 +1,5 @@
from functools import lru_cache
from pydantic_settings import BaseSettings
from pydantic import ConfigDict
from typing import Annotated, Set
@@ -28,3 +29,7 @@ class Settings(BaseSettings):
ALLOWED_ORIGINS: Annotated[set[str], Len(min_length=1)]
CHROME_APP_IDS: Annotated[set[Annotated[str, Len(min_length=10)]], Len(min_length=1)]
BLOCKED_EMAILS: Annotated[Set[str], Len(min_length=0)] = set()
@lru_cache
def get_settings():
return Settings()

View File

@@ -13,7 +13,7 @@ def mock_logger_add():
@pytest.fixture()
def settings():
def get_settings():
return Settings(_env_file=".env.test")
@pytest.fixture(autouse=True)
@@ -23,13 +23,13 @@ def mock_settings():
@pytest.fixture()
def test_db(settings: Settings):
def test_db(get_settings: Settings):
from db.database import make_engine
from db import models
engine = make_engine(settings.DATABASE_PATH)
engine = make_engine(get_settings.DATABASE_PATH)
fs = settings.DATABASE_PATH.replace("sqlite:///", "")
fs = get_settings.DATABASE_PATH.replace("sqlite:///", "")
if not os.path.exists(fs):
open(fs, 'w').close()

View File

@@ -135,7 +135,6 @@ def test_search_archives_by_url(test_data, db_session):
def test_search_archives_by_email(test_data, db_session):
from web.security import ALLOW_ANY_EMAIL
from db import crud
from web.security import ALLOW_ANY_EMAIL
# lower/upper case
assert len(crud.search_archives_by_email(db_session, "rick@example.com")) == 34
@@ -363,13 +362,13 @@ def test_get_group(test_data, db_session):
def test_upsert_user_groups(db_session):
from db import crud
@patch('db.crud.Settings', new = lambda: bad_setings)
@patch('db.crud.get_settings', new = lambda: bad_setings)
def test_missing_yaml(db_session):
with pytest.raises(FileNotFoundError):
crud.upsert_user_groups(db_session)
@patch('db.crud.Settings', new = lambda: bad_setings)
@patch('db.crud.get_settings', new = lambda: bad_setings)
def test_broken_yaml(db_session):
with pytest.raises(yaml.YAMLError):
crud.upsert_user_groups(db_session)

View File

@@ -1,11 +1,11 @@
import os
from fastapi.testclient import TestClient
from shared.settings import Settings
from shared.settings import get_settings
import shutil
def test_serve_local_archive_logic(settings: Settings):
def test_serve_local_archive_logic(get_settings):
# create a test file first
os.makedirs("local_archive_test", exist_ok=True)
with open("local_archive_test/temp.txt", "w") as f:
@@ -13,9 +13,9 @@ def test_serve_local_archive_logic(settings: Settings):
try:
# modify the settings
settings.SERVE_LOCAL_ARCHIVE = "/app/local_archive_test"
get_settings.SERVE_LOCAL_ARCHIVE = "/app/local_archive_test"
from web.main import app_factory
app = app_factory(settings)
app = app_factory(get_settings)
# test
client = TestClient(app)

View File

@@ -0,0 +1,104 @@
from unittest.mock import patch
from fastapi import HTTPException
from fastapi.security import HTTPAuthorizationCredentials
import pytest
def test_secure_compare():
from web.security import secure_compare
assert secure_compare("test", "test")
assert not secure_compare("test", "test2")
@pytest.mark.asyncio
async def test_get_token_or_user_auth_with_api():
from web.security import get_token_or_user_auth, ALLOW_ANY_EMAIL
mock_api = HTTPAuthorizationCredentials(scheme="lorem", credentials="this_is_the_test_api_token")
assert await get_token_or_user_auth(mock_api) == ALLOW_ANY_EMAIL
@pytest.mark.asyncio
async def test_get_token_or_user_auth_with_user():
from web.security import get_token_or_user_auth
bad_user = HTTPAuthorizationCredentials(scheme="ipsum", credentials="invalid")
with pytest.raises(HTTPException) as e:
await get_token_or_user_auth(bad_user)
assert e.status_code == 401
assert e.detail == "invalid access_token"
@patch("web.security.authenticate_user", return_value=(True, "summer@example.com"))
@pytest.mark.asyncio
async def test_get_user_auth(m1):
from web.security import get_user_auth
bad_user = HTTPAuthorizationCredentials(scheme="ipsum", credentials="valid-and-good")
assert await get_user_auth(bad_user) == "summer@example.com"
@patch("web.security.secure_compare", return_value=False)
@pytest.mark.asyncio
async def test_token_api_key_auth_exception(m1):
from web.security import token_api_key_auth
with pytest.raises(HTTPException) as e:
await token_api_key_auth(HTTPAuthorizationCredentials(scheme="ipsum", credentials="does-not-matter"), auto_error=True)
assert e.status_code == 401
assert e.detail == "Wrong auth credentials"
@pytest.mark.asyncio
async def test_authenticate_user():
from web.security import authenticate_user
assert authenticate_user("test") == (False, "invalid access_token")
assert authenticate_user(123) == (False, "invalid access_token")
with patch("web.security.requests.get") as mock_get:
# bad response from oauth2
mock_get.return_value.status_code = 403
assert authenticate_user("this-will-call-requests") == (False, "invalid token")
assert mock_get.call_count == 1
# 200 but invalid json
mock_get.return_value.status_code = 200
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
assert mock_get.call_count == 2
# 200 but invalid azp and aud
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
mock_get.return_value.json.return_value = {"email": "summer@example.com", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
# blocked email
mock_get.return_value.json.return_value = {"email": "blocked@example.com", "azp": "test_app_id_1", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "email 'blocked@example.com' not allowed")
# not verified
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app", "aud": "test_app_id_1"}
assert authenticate_user("this-will-call-requests") == (False, "email 'summer@example.com' not verified")
# token expired
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "test_app_id_2", "email_verified": "true"}
assert authenticate_user("this-will-call-requests") == (False, "Token expired")
# 200 and valid azp and aup and verified
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "test_app_id_2", "email_verified": "true", "expires_in": 100}
assert authenticate_user("this-will-call-requests") == (True, "summer@example.com")
assert mock_get.call_count == 9
@pytest.mark.asyncio
async def test_authenticate_user_exception():
from web.security import authenticate_user
with patch("web.security.requests.get") as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.side_effect = Exception("mocked error")
assert authenticate_user("this-will-call-requests") == (False, "exception occurred")

View File

@@ -19,14 +19,14 @@ from web.security import get_user_auth, token_api_key_auth, get_token_or_user_au
from core.config import VERSION, API_DESCRIPTION
from db.database import get_db_dependency
from core.events import lifespan
from shared.settings import Settings
from shared.settings import get_settings
from auto_archiver import Metadata
from endpoints import default_router, url_router, sheet_router, task_router, interoperability_router
def app_factory(settings = Settings()):
def app_factory(settings = get_settings()):
app = FastAPI(
title="Auto-Archiver API",
description=API_DESCRIPTION,

View File

@@ -1,12 +1,12 @@
from loguru import logger
import requests, os, secrets
import requests, secrets
from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from shared.settings import Settings
from shared.settings import get_settings
ALLOW_ANY_EMAIL = "*"
settings = Settings()
settings = get_settings()
bearer_security = HTTPBearer()
@@ -39,15 +39,15 @@ token_api_key_auth = api_key_auth(settings.API_BEARER_TOKEN)
async def get_token_or_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)):
# tries to use the static API_KEY and defaults to google JWT auth
access_token = credentials.credentials
if token_api_key_auth(access_token, auto_error=False): return ALLOW_ANY_EMAIL
if await token_api_key_auth(credentials, auto_error=False): return ALLOW_ANY_EMAIL
return await get_user_auth(credentials)
async def get_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)):
# validates the Bearer token in the case that it requires it
valid_user, info = authenticate_user(credentials.credentials)
if valid_user: return info
if valid_user:
return info
logger.debug(f"TOKEN FAILURE: {valid_user=} {info=}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@@ -73,5 +73,5 @@ def authenticate_user(access_token):
return False, "Token expired"
return True, j.get('email')
except Exception as e:
logger.warning(f"EXCEPTION occurred: {e}")
return False, f"EXCEPTION occurred"
logger.warning(f"AUTH EXCEPTION occurred: {e}")
return False, "exception occurred"

View File

@@ -10,12 +10,12 @@ from loguru import logger
from db import crud, schemas, models
from db.database import get_db
from shared.settings import Settings
from shared.settings import get_settings
import json
import redis
from sqlalchemy import exc
settings = Settings()
settings = get_settings()
celery = Celery(__name__)
celery.conf.broker_url = settings.CELERY_BROKER_URL