diff --git a/backend/routers/auth_router.py b/backend/routers/auth_router.py index 3f18f7e..98ede29 100644 --- a/backend/routers/auth_router.py +++ b/backend/routers/auth_router.py @@ -1,3 +1,4 @@ +from datetime import timedelta from typing import Optional import pyotp @@ -11,6 +12,9 @@ import models from auth import create_access_token, get_current_user, get_password_hash, verify_password from database import get_db +# When "Angemeldet bleiben" is ticked the token lives for half a year. +REMEMBER_ME_EXPIRY = timedelta(days=180) + router = APIRouter() @@ -24,6 +28,7 @@ class LoginRequest(BaseModel): username: str password: str totp_code: Optional[str] = None + remember_me: Optional[bool] = False def _user_dict(user: models.User) -> dict: @@ -98,7 +103,8 @@ def login_json(req: LoginRequest, db: Session = Depends(get_db)): status_code=status.HTTP_401_UNAUTHORIZED, detail="Ungültiger 2FA-Code", ) - token = create_access_token({"sub": user.username}) + expires = REMEMBER_ME_EXPIRY if req.remember_me else None + token = create_access_token({"sub": user.username}, expires_delta=expires) return {"access_token": token, "token_type": "bearer", "user": _user_dict(user)} diff --git a/frontend/index.html b/frontend/index.html index 4a90364..6565e70 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - Calendarr v5 + Calendarr v6 @@ -73,11 +73,14 @@ + - + @@ -196,7 +199,7 @@
- + @@ -232,7 +235,7 @@
- +
@@ -240,7 +243,7 @@
- +
@@ -250,7 +253,7 @@
- +
@@ -258,7 +261,7 @@
- +
@@ -308,7 +311,7 @@
- +
@@ -862,7 +865,7 @@ scarriffleservices@gmail.com

diff --git a/frontend/js/api.js b/frontend/js/api.js index 38b4a1e..b715277 100644 --- a/frontend/js/api.js +++ b/frontend/js/api.js @@ -64,8 +64,8 @@ export const api = { delete: (path) => request('DELETE', path), upload: (path, form) => uploadRequest(path, form), - login: (username, password, totp_code = null) => - request('POST', '/auth/login', { username, password, totp_code }), + login: (username, password, totp_code = null, remember_me = false) => + request('POST', '/auth/login', { username, password, totp_code, remember_me }), setupRequired: () => request('GET', '/auth/setup-required'), setup: (data) => request('POST', '/auth/setup', data), diff --git a/frontend/js/app.js b/frontend/js/app.js index c33fed0..cf2c277 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -141,11 +141,12 @@ function bindLoginForm() { const username = document.getElementById('login-username').value.trim(); const password = document.getElementById('login-password').value; const totpCode = document.getElementById('login-totp')?.value.trim() || null; + const remember = document.getElementById('login-remember')?.checked || false; const errEl = document.getElementById('login-error'); errEl.classList.add('hidden'); try { - const res = await api.login(username, password, totpCode); + const res = await api.login(username, password, totpCode, remember); localStorage.setItem('token', res.access_token); localStorage.setItem('user', JSON.stringify(res.user)); await launchApp(); diff --git a/frontend/js/version.js b/frontend/js/version.js index d5ed145..bc8e7e5 100644 --- a/frontend/js/version.js +++ b/frontend/js/version.js @@ -1,2 +1,2 @@ // Increment APP_VERSION with every code change -export const APP_VERSION = 'v5'; +export const APP_VERSION = 'v6'; diff --git a/frontend/sw.js b/frontend/sw.js index 4783304..3e9316e 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,7 +1,7 @@ // Calendarr Service Worker // Cache-first for static assets, network-first for /api/* (graceful offline) -const CACHE_VERSION = 'calendarr-v5'; +const CACHE_VERSION = 'calendarr-v6'; const STATIC_ASSETS = [ '/', '/index.html',