finish for init core
This commit is contained in:
@ -4,8 +4,7 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
from .settings import AppDirectories, AppSettings
|
||||
from fuware.core.settings.settings import AppSettings, app_settings_constructor
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
BASE_DIR = CWD.parent.parent
|
||||
@ -27,14 +26,6 @@ def determine_data_dir() -> Path:
|
||||
|
||||
return BASE_DIR.joinpath("dev", "data")
|
||||
|
||||
@lru_cache
|
||||
def get_app_dirs() -> AppDirectories:
|
||||
return AppDirectories(determine_data_dir())
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_app_settings() -> AppSettings:
|
||||
return app_settings_constructor(env_file=ENV, production=PRODUCTION, data_dir=determine_data_dir())
|
||||
|
||||
|
||||
print(get_app_settings())
|
||||
|
1
fuware/core/dependencies/__init__.py
Normal file
1
fuware/core/dependencies/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .dependencies import *
|
20
fuware/core/dependencies/dependencies.py
Normal file
20
fuware/core/dependencies/dependencies.py
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
from fastapi import Depends, HTTPException, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from fuware.core.config import get_app_settings
|
||||
from fuware.db.db_setup import generate_session
|
||||
|
||||
settings = get_app_settings()
|
||||
|
||||
async def get_auth_user(request: Request, db: Session = Depends(generate_session)):
|
||||
"""verify that user has a valid session"""
|
||||
session_id = request.cookies.get(settings.COOKIE_KEY)
|
||||
if not session_id:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
# decrypt_user = decryptString(session_id).split(',')
|
||||
# db_user = get_user_by_username(db, decrypt_user[0])
|
||||
# if not db_user:
|
||||
# raise HTTPException(status_code=403)
|
||||
# if not verify_password(decrypt_user[1], db_user.password):
|
||||
# raise HTTPException(status_code=401, detail="Your username or password input is wrong!")
|
||||
return True
|
67
fuware/core/logger/config.py
Normal file
67
fuware/core/logger/config.py
Normal file
@ -0,0 +1,67 @@
|
||||
import json
|
||||
import logging
|
||||
import pathlib
|
||||
import typing
|
||||
from logging import config as logging_config
|
||||
|
||||
__dir = pathlib.Path(__file__).parent
|
||||
__conf: dict[str, str] | None = None
|
||||
|
||||
|
||||
def _load_config(path: pathlib.Path, substitutions: dict[str, str] | None = None) -> dict[str, typing.Any]:
|
||||
with open(path) as file:
|
||||
if substitutions:
|
||||
contents = file.read()
|
||||
for key, value in substitutions.items():
|
||||
# Replaces the key matches
|
||||
#
|
||||
# Example:
|
||||
# {"key": "value"}
|
||||
# "/path/to/${key}/file" -> "/path/to/value/file"
|
||||
contents = contents.replace(f"${{{key}}}", value)
|
||||
|
||||
json_data = json.loads(contents)
|
||||
|
||||
else:
|
||||
json_data = json.load(file)
|
||||
|
||||
return json_data
|
||||
|
||||
|
||||
def log_config() -> dict[str, str]:
|
||||
if __conf is None:
|
||||
raise ValueError("logger not configured, must call configured_logger first")
|
||||
|
||||
return __conf
|
||||
|
||||
|
||||
def configured_logger(
|
||||
*,
|
||||
mode: str,
|
||||
config_override: pathlib.Path | None = None,
|
||||
substitutions: dict[str, str] | None = None,
|
||||
) -> logging.Logger:
|
||||
"""
|
||||
Configure the logger based on the mode and return the root logger
|
||||
|
||||
Args:
|
||||
mode (str): The mode to configure the logger for (production, development, testing)
|
||||
config_override (pathlib.Path, optional): A path to a custom logging config. Defaults to None.
|
||||
substitutions (dict[str, str], optional): A dictionary of substitutions to apply to the logging config.
|
||||
"""
|
||||
global __conf
|
||||
|
||||
if config_override:
|
||||
__conf = _load_config(config_override, substitutions)
|
||||
else:
|
||||
if mode == "production":
|
||||
__conf = _load_config(__dir / "logconf.prod.json", substitutions)
|
||||
elif mode == "development":
|
||||
__conf = _load_config(__dir / "logconf.dev.json", substitutions)
|
||||
elif mode == "testing":
|
||||
__conf = _load_config(__dir / "logconf.test.json", substitutions)
|
||||
else:
|
||||
raise ValueError(f"Invalid mode: {mode}")
|
||||
|
||||
logging_config.dictConfig(config=__conf)
|
||||
return logging.getLogger()
|
0
fuware/core/security/__init__.py
Normal file
0
fuware/core/security/__init__.py
Normal file
34
fuware/core/security/hasher.py
Normal file
34
fuware/core/security/hasher.py
Normal file
@ -0,0 +1,34 @@
|
||||
from functools import lru_cache
|
||||
from typing import Protocol
|
||||
import bcrypt
|
||||
|
||||
from fuware.core.config import get_app_settings
|
||||
|
||||
|
||||
class Hasher(Protocol):
|
||||
def hash(self, password: str) -> str: ...
|
||||
|
||||
def verify(self, password: str, hashed: str) -> bool: ...
|
||||
|
||||
class FakeHasher:
|
||||
def hash(self, password: str) -> str:
|
||||
return password
|
||||
|
||||
def verify(self, password: str, hashed: str) -> bool:
|
||||
return password == hashed
|
||||
|
||||
class BcryptHasher:
|
||||
def hash(self, password: str) -> str:
|
||||
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
||||
|
||||
def verify(self, password: str, hashed: str) -> bool:
|
||||
return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_hasher() -> Hasher:
|
||||
settings = get_app_settings()
|
||||
|
||||
if settings.TESTING:
|
||||
return FakeHasher()
|
||||
|
||||
return BcryptHasher()
|
@ -17,7 +17,7 @@ class SQLiteProvider(AbstractDBProvider, BaseModel):
|
||||
|
||||
@property
|
||||
def db_path(self):
|
||||
return self.data_dir / f"{self.prefix}mealie.db"
|
||||
return self.data_dir / f"{self.prefix}fuware.db"
|
||||
|
||||
@property
|
||||
def db_url(self) -> str:
|
||||
|
@ -1,26 +1,23 @@
|
||||
import secrets
|
||||
from pathlib import Path
|
||||
from fuware.core.settings.db_providers import AbstractDBProvider, SQLiteProvider
|
||||
from pydantic_settings import BaseSettings # type: ignore
|
||||
|
||||
|
||||
def determine_secrets(data_dir: Path, production: bool) -> str:
|
||||
def determine_secrets(production: bool) -> str:
|
||||
if not production:
|
||||
return "shh-secret-test-key"
|
||||
|
||||
secrets_file = data_dir.joinpath(".secret")
|
||||
if secrets_file.is_file():
|
||||
with open(secrets_file) as f:
|
||||
return f.read()
|
||||
else:
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(secrets_file, "w") as f:
|
||||
new_secret = secrets.token_hex(32)
|
||||
f.write(new_secret)
|
||||
return new_secret
|
||||
return "oWNhXlfo666JlMHk6UHYxeNB6z_CA2MisDDZJe4N0yc="
|
||||
|
||||
def determine_cookie(production: bool) -> str:
|
||||
if not production:
|
||||
return "logcook"
|
||||
|
||||
return "7fo24CMyIc"
|
||||
|
||||
class AppSettings(BaseSettings):
|
||||
PRODUCTION: bool
|
||||
TESTING: bool
|
||||
BASE_URL: str = "http://localhost:8080"
|
||||
"""trailing slashes are trimmed (ex. `http://localhost:8080/` becomes ``http://localhost:8080`)"""
|
||||
|
||||
@ -32,6 +29,9 @@ class AppSettings(BaseSettings):
|
||||
|
||||
ALLOW_SIGNUP: bool = False
|
||||
|
||||
SECRET: str
|
||||
COOKIE_KEY: str
|
||||
|
||||
@property
|
||||
def DOCS_URL(self) -> str | None:
|
||||
return "/docs" if self.API_DOCS else None
|
||||
@ -43,7 +43,6 @@ class AppSettings(BaseSettings):
|
||||
# ===============================================
|
||||
# Database Configuration
|
||||
|
||||
DB_ENGINE: str = "sqlite" # Options: 'sqlite', 'postgres'
|
||||
DB_PROVIDER: AbstractDBProvider | None = None
|
||||
|
||||
@property
|
||||
@ -63,7 +62,7 @@ def app_settings_constructor(data_dir: Path, production: bool, env_file: Path, e
|
||||
app_settings = AppSettings(
|
||||
_env_file=env_file, # type: ignore
|
||||
_env_file_encoding=env_encoding, # type: ignore
|
||||
**{"SECRET": determine_secrets(data_dir, production)},
|
||||
**{"SECRET": determine_secrets(production), 'COOKIE_KEY': determine_cookie(production)},
|
||||
)
|
||||
|
||||
app_settings.DB_PROVIDER = SQLiteProvider(data_dir=data_dir)
|
||||
|
@ -1,22 +0,0 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from pathlib import Path
|
||||
from fuware import __version__
|
||||
|
||||
load_dotenv()
|
||||
|
||||
APP_VERSION = __version__
|
||||
CWD = Path(__file__).parent
|
||||
BASE_DIR = CWD.parent.parent.parent
|
||||
|
||||
SERCET_KEY = b"oWNhXlfo666JlMHk6UHYxeNB6z_CA2MisDDZJe4N0yc="
|
||||
COOKIE_KEY = os.getenv('VITE_LOGIN_KEY') or '7fo24CMyIc'
|
||||
# URL_DATABASE = "postgresql://{0}:{1}@{2}:{3}/{4}".format(
|
||||
# os.getenv('LOL_DB_USER'),
|
||||
# os.getenv('LOL_DB_PASSWORD'),
|
||||
# os.getenv('LOL_DB_HOST'),
|
||||
# os.getenv('LOL_DB_PORT'),
|
||||
# os.getenv('LOL_DB_NAME'),
|
||||
# )
|
||||
URL_DATABASE = "sqlite:///./test.db"
|
Reference in New Issue
Block a user