Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #18

Merged
merged 7 commits into from
Jul 26, 2024
Merged

Dev #18

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
11 changes: 8 additions & 3 deletions src/api/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def password_check_hash(cls, password: SecretStr) -> str:
raise ValueError("Make sure your password has a number in it")
elif re.search("[A-Z]", pswd) is None and SignupConfig.password_complexity >= 3:
raise ValueError("Make sure your password has a capital letter in it")
elif re.search("[^a-zA-Z0-9]", pswd) is None and SignupConfig.password_complexity >= 4:
elif (
re.search("[^a-zA-Z0-9]", pswd) is None
and SignupConfig.password_complexity >= 4
):
raise ValueError("Make sure your password has a special character in it")
elif len(pswd) > 50:
raise ValueError("Make sure your password is at most 50 characters")
Expand Down Expand Up @@ -98,9 +101,11 @@ def username_check(cls, username: str) -> str:
if len(username) == 0:
raise ValueError("Username cannot be empty")
if len(username) < 4:
if SignupConfig.username_complexity >= 1: raise ValueError("Username must be at least 4 characters long")
if SignupConfig.username_complexity >= 1:
raise ValueError("Username must be at least 4 characters long")
if len(username) > 20:
if SignupConfig.username_complexity >= 2: raise ValueError("Username must be at most 20 characters long")
if SignupConfig.username_complexity >= 2:
raise ValueError("Username must be at most 20 characters long")
elif re.search("[^a-zA-Z0-9]", username) is not None:
raise ValueError("Username must only contain letters and numbers")
return username
2 changes: 1 addition & 1 deletion src/api/oauth_providers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from fastapi import APIRouter
from tools.conf import SignupConfig
from tools import SignupConfig

router = APIRouter(
prefix="/oauth",
Expand Down
10 changes: 8 additions & 2 deletions src/api/oauth_providers/github.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from fastapi import APIRouter, Request, BackgroundTasks, Response, HTTPException
from fastapi.responses import RedirectResponse
from tools.conf import SignupConfig, SessionConfig
from tools import SignupConfig, SessionConfig
import json
import requests
import re
Expand All @@ -13,7 +13,13 @@
from crud.sessions import create_login_session
from api.model import LoginResponse

github_cnf = json.load(open("/src/app/config/github_client_secret.env.json"))
try:
github_cnf = json.load(open("/src/app/config/github_client_secret.env.json"))
except FileNotFoundError:
raise FileNotFoundError(
"GitHub OAuth Config File not found (github_client_secret.env.json).\
Please disable this OAuth Provider, or create the file as described in the Docs."
)
REDIRECT_URI = SignupConfig.oauth_base_url + "/oauth/github/callback"
CLIENT_ID = github_cnf["client_id"]
CLIENT_SECRET = github_cnf["client_secret"]
Expand Down
24 changes: 15 additions & 9 deletions src/api/oauth_providers/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,21 @@
)

# Initialize Googles OAuth Flow
flow = Flow.from_client_secrets_file(
client_secrets_file="/src/app/config/google_client_secret.env.json",
scopes=[
"https://www.googleapis.com/auth/userinfo.email",
"openid",
"https://www.googleapis.com/auth/userinfo.profile",
],
redirect_uri=SignupConfig.oauth_base_url + "/oauth/google/callback",
)
try:
flow = Flow.from_client_secrets_file(
client_secrets_file="/src/app/config/google_client_secret.env.json",
scopes=[
"https://www.googleapis.com/auth/userinfo.email",
"openid",
"https://www.googleapis.com/auth/userinfo.profile",
],
redirect_uri=SignupConfig.oauth_base_url + "/oauth/google/callback",
)
except FileNotFoundError:
raise FileNotFoundError(
"Google OAuth Config File not found (google_client_secret.env.json).\
Please disable this OAuth Provider, or create the file as described in the Docs."
)


@router.get("/login")
Expand Down
2 changes: 1 addition & 1 deletion src/api/profile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks, Response
from tools.conf import AccountFeaturesConfig, SignupConfig
from tools import AccountFeaturesConfig, SignupConfig
from api.model import ResetPasswordRequest, ConfirmEmailRequest, DeleteAccountRequest
import json
import bcrypt
Expand Down
2 changes: 1 addition & 1 deletion src/crud/sessions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import uuid
from tools import sessions_collection, users_collection
import datetime
from tools.conf import SessionConfig
from tools import SessionConfig
from fastapi import Request
from user_agents import parse
from bson import ObjectId, errors
Expand Down
12 changes: 6 additions & 6 deletions src/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from .db import users_collection, sessions_collection, bson_to_json, r
from .conf import (
SignupConfig,
EmailConfig,
SessionConfig,
InternalConfig,
AccountFeaturesConfig,
default_signup_fields,
insecure_cols,
SecurityConfig,
default_signup_fields,
AccountFeaturesConfig,
InternalConfig,
SessionConfig,
EmailConfig,
SignupConfig,
)
from .mail import send_email, broadcast_emails
from .confirmation_codes import all_ids, regenerate_ids
Expand Down
88 changes: 0 additions & 88 deletions src/tools/conf.py

This file was deleted.

90 changes: 90 additions & 0 deletions src/tools/conf/AccountFeaturesConfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from .conf import config, not_updateable_cols_internal


class AccountFeaturesConfig:
enable_reset_pswd: bool = config["account_features"]["enable_reset_pswd"]
reset_pswd_conf_mail: bool = config["account_features"]["reset_pswd_conf_mail"]
enable_2fa: bool = config["account_features"]["2fa"]["enable"]
issuer_name_2fa: str = config["account_features"]["2fa"]["issuer_name"]
issuer_image_url_2fa: str = config["account_features"]["2fa"]["issuer_image_url"]
qr_code_endpoint_2fa: bool = config["account_features"]["2fa"]["qr_endpoint"]

if not isinstance(config["account_features"]["allow_add_fields_on_signup"], list):
raise ValueError(
"account_features.allow_add_fields_on_signup must be a list (got type {})".format(
type(config["account_features"]["allow_add_fields_on_signup"])
)
)

allow_add_fields_on_signup: set[str] = set(
config["account_features"]["allow_add_fields_on_signup"]
) - set(not_updateable_cols_internal)

if not isinstance(config["account_features"]["allow_add_fields_patch_user"], list):
raise ValueError(
"account_features.allow_add_fields_patch_user must be a list (got type {})".format(
type(config["account_features"]["allow_add_fields_patch_user"])
)
)

allow_add_fields_patch_user: set[str] = set(
config["account_features"]["allow_add_fields_patch_user"]
) - set(not_updateable_cols_internal)
allow_deletion: bool = config["account_features"]["allow_deletion"]
deletion_pending_minutes: int = config["account_features"][
"deletion_pending_minutes"
]

def validate_types(self) -> bool:
"""This is to Type Check the Configuration"""
if not isinstance(self.enable_reset_pswd, bool):
raise ValueError(
"account_features.enable_reset_pswd must be a boolean (got type {})".format(
type(self.enable_reset_pswd)
)
)
if not isinstance(self.reset_pswd_conf_mail, bool):
raise ValueError(
"account_features.reset_pswd_conf_mail must be a boolean (got type {})".format(
type(self.reset_pswd_conf_mail)
)
)
if not isinstance(self.enable_2fa, bool):
raise ValueError(
"account_features.2fa.enable must be a boolean (got type {})".format(
type(self.enable_2fa)
)
)
if not isinstance(self.issuer_name_2fa, str):
raise ValueError(
"account_features.2fa.issuer_name must be a string (got type {})".format(
type(self.issuer_name_2fa)
)
)
if not isinstance(self.issuer_image_url_2fa, str):
raise ValueError(
"account_features.2fa.issuer_image_url must be a string (got type {})".format(
type(self.issuer_image_url_2fa)
)
)
if not isinstance(self.qr_code_endpoint_2fa, bool):
raise ValueError(
"account_features.2fa.qr_endpoint must be a boolean (got type {})".format(
type(self.qr_code_endpoint_2fa)
)
)
if not isinstance(self.allow_deletion, bool):
raise ValueError(
"account_features.allow_deletion must be a boolean (got type {})".format(
type(self.allow_deletion)
)
)
if not isinstance(self.deletion_pending_minutes, int):
raise ValueError(
"account_features.deletion_pending_minutes must be an integer (got type {})".format(
type(self.deletion_pending_minutes)
)
)


AccountFeaturesConfig().validate_types()
45 changes: 45 additions & 0 deletions src/tools/conf/EmailConfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from .conf import config


class EmailConfig:
login_usr: str = config["email"]["login_usr"]
login_pwd: str = config["email"]["login_pwd"]
sender_email: str = config["email"]["sender_email"]
smtp_host: str = config["email"]["smtp_host"]
smtp_port: int = config["email"]["smtp_port"]

def validate_types(self) -> None:
"""This is to Type Check the Configuration"""
if not isinstance(self.login_usr, str):
raise ValueError(
"email.login_usr must be a string (got type {})".format(
type(self.login_usr)
)
)
if not isinstance(self.login_pwd, str):
raise ValueError(
"email.login_pwd must be a string (got type {})".format(
type(self.login_pwd)
)
)
if not isinstance(self.sender_email, str):
raise ValueError(
"email.sender_email must be a string (got type {})".format(
type(self.sender_email)
)
)
if not isinstance(self.smtp_host, str):
raise ValueError(
"email.smtp_host must be a string (got type {})".format(
type(self.smtp_host)
)
)
if not isinstance(self.smtp_port, int):
raise ValueError(
"email.smtp_port must be an integer (got type {})".format(
type(self.smtp_port)
)
)


EmailConfig().validate_types()
41 changes: 41 additions & 0 deletions src/tools/conf/InternalConfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from .conf import config, insecure_cols, not_updateable_cols_internal
from collections import ChainMap


class InternalConfig:
internal_api_key: str = config["internal"]["internal_api_key"]
# Type Check here because calculations need to be done immediately
if not isinstance(config["internal"]["internal_columns"], list):
raise ValueError(
"internal.internal_columns must be a list (got type {})".format(
type(config["internal"]["internal_columns"])
)
)
internal_columns: dict = dict(
ChainMap(*[{col: 0} for col in set(config["internal"]["internal_columns"])])
)
internal_columns.update(insecure_cols)
# Insecure Cols + Internal Cols can't be updated by the user
if not isinstance(config["internal"]["not_updateable_columns"], list):
raise ValueError(
"internal.not_updateable_columns must be a list (got type {})".format(
type(config["internal"]["not_updateable_columns"])
)
)
not_updateable_columns: set = set(
config["internal"]["not_updateable_columns"]
+ list(internal_columns.keys())
+ not_updateable_cols_internal
)

def validate_types(self) -> bool:
"""This is to Type Check the Configuration"""
if not isinstance(self.internal_api_key, str):
raise ValueError(
"internal.internal_api_key must be a string (got type {})".format(
type(self.internal_api_key)
)
)


InternalConfig().validate_types()
Loading
Loading