Validate setup and login credential inputs
All checks were successful
docker / build-and-push (push) Successful in 49s
All checks were successful
docker / build-and-push (push) Successful in 49s
This commit is contained in:
@@ -42,6 +42,8 @@ The app expects a MariaDB instance configured through environment variables.
|
|||||||
- `LOGIN_WINDOW_SECONDS` (default: `300`)
|
- `LOGIN_WINDOW_SECONDS` (default: `300`)
|
||||||
- `LOGIN_LOCKOUT_SECONDS` (default: `900`)
|
- `LOGIN_LOCKOUT_SECONDS` (default: `900`)
|
||||||
- `MAX_ICON_BYTES` (default: `2097152`)
|
- `MAX_ICON_BYTES` (default: `2097152`)
|
||||||
|
- `USERNAME_MAX_LEN` (default: `64`)
|
||||||
|
- `PASSWORD_MIN_LEN` (default: `12`)
|
||||||
|
|
||||||
## Gitea CI/CD
|
## Gitea CI/CD
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ MAX_DESCRIPTION_LEN = int(os.getenv("MAX_DESCRIPTION_LEN", "2000"))
|
|||||||
MAX_ICON_URL_LEN = int(os.getenv("MAX_ICON_URL_LEN", "2048"))
|
MAX_ICON_URL_LEN = int(os.getenv("MAX_ICON_URL_LEN", "2048"))
|
||||||
MAX_ICON_BYTES = int(os.getenv("MAX_ICON_BYTES", str(2 * 1024 * 1024)))
|
MAX_ICON_BYTES = int(os.getenv("MAX_ICON_BYTES", str(2 * 1024 * 1024)))
|
||||||
ALLOWED_ICON_MIME = {"image/png", "image/jpeg", "image/webp", "image/gif", "image/svg+xml", "image/x-icon"}
|
ALLOWED_ICON_MIME = {"image/png", "image/jpeg", "image/webp", "image/gif", "image/svg+xml", "image/x-icon"}
|
||||||
|
USERNAME_MAX_LEN = int(os.getenv("USERNAME_MAX_LEN", "64"))
|
||||||
|
PASSWORD_MIN_LEN = int(os.getenv("PASSWORD_MIN_LEN", "12"))
|
||||||
DB_HOST = os.getenv("DB_HOST", "mariadb")
|
DB_HOST = os.getenv("DB_HOST", "mariadb")
|
||||||
DB_PORT = int(os.getenv("DB_PORT", "3306"))
|
DB_PORT = int(os.getenv("DB_PORT", "3306"))
|
||||||
DB_USER = os.getenv("DB_USER", "jellomator")
|
DB_USER = os.getenv("DB_USER", "jellomator")
|
||||||
@@ -276,6 +278,15 @@ def validate_http_url(value: str, field_name: str = "url") -> None:
|
|||||||
raise HTTPException(422, f"{field_name} must be a valid http(s) URL")
|
raise HTTPException(422, f"{field_name} must be a valid http(s) URL")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_credentials(username: str, password: str) -> None:
|
||||||
|
if not username or len(username.strip()) == 0:
|
||||||
|
raise HTTPException(422, "username is required")
|
||||||
|
if len(username) > USERNAME_MAX_LEN:
|
||||||
|
raise HTTPException(422, f"username exceeds max length of {USERNAME_MAX_LEN}")
|
||||||
|
if len(password or "") < PASSWORD_MIN_LEN:
|
||||||
|
raise HTTPException(422, f"password must be at least {PASSWORD_MIN_LEN} characters")
|
||||||
|
|
||||||
|
|
||||||
def validate_length(value: str | None, limit: int, field_name: str) -> None:
|
def validate_length(value: str | None, limit: int, field_name: str) -> None:
|
||||||
if value is not None and len(value) > limit:
|
if value is not None and len(value) > limit:
|
||||||
raise HTTPException(422, f"{field_name} exceeds max length of {limit}")
|
raise HTTPException(422, f"{field_name} exceeds max length of {limit}")
|
||||||
@@ -314,6 +325,7 @@ def me(request: Request, response: Response):
|
|||||||
|
|
||||||
@app.post("/api/setup")
|
@app.post("/api/setup")
|
||||||
def setup(inp: SetupIn):
|
def setup(inp: SetupIn):
|
||||||
|
validate_credentials(inp.username, inp.password)
|
||||||
with db() as c:
|
with db() as c:
|
||||||
with c.cursor() as cur:
|
with c.cursor() as cur:
|
||||||
cur.execute("select count(*) as count from users")
|
cur.execute("select count(*) as count from users")
|
||||||
@@ -326,6 +338,7 @@ def setup(inp: SetupIn):
|
|||||||
|
|
||||||
@app.post("/api/login")
|
@app.post("/api/login")
|
||||||
def login(request: Request, inp: LoginIn):
|
def login(request: Request, inp: LoginIn):
|
||||||
|
validate_credentials(inp.username, inp.password)
|
||||||
now_ts = time.time()
|
now_ts = time.time()
|
||||||
prune_login_tracking(now_ts)
|
prune_login_tracking(now_ts)
|
||||||
key = login_key(request, inp.username)
|
key = login_key(request, inp.username)
|
||||||
|
|||||||
Reference in New Issue
Block a user