diff --git a/dashboard/backend/requirements.txt b/dashboard/backend/requirements.txt index 758f167..707d126 100644 --- a/dashboard/backend/requirements.txt +++ b/dashboard/backend/requirements.txt @@ -11,3 +11,4 @@ asyncssh==2.17.0 slowapi==0.1.9 webauthn==2.7.1 cryptography>=44.0.2 +aiosqlite diff --git a/dashboard/backend/routers/auth.py b/dashboard/backend/routers/auth.py index 467eeb5..faf777b 100644 --- a/dashboard/backend/routers/auth.py +++ b/dashboard/backend/routers/auth.py @@ -109,6 +109,30 @@ async def login(creds: LoginRequest, request: Request): "has_2fa": bool(totp_secret) } +@router.get("/proxy") +async def proxy_auth(request: Request): + """Auto-login when Authelia has already authenticated the user via forward-auth. + Caddy sets Remote-User header after successful Authelia 2FA verification.""" + remote_user = request.headers.get("Remote-User") + if not remote_user: + raise HTTPException(status_code=401, detail="No proxy auth header") + # Map the LDAP user to the dashboard admin user + # Only allow known users (the admin) + if remote_user != config.ADMIN_USER: + raise HTTPException(status_code=403, detail="User not authorized for dashboard") + access_token = auth.create_access_token( + data={"sub": remote_user}, + expires_delta=timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES), + ) + refresh_token = auth.create_refresh_token(data={"sub": remote_user}) + return { + "access_token": access_token, + "refresh_token": refresh_token, + "token_type": "bearer", + "user": remote_user, + "has_2fa": True, + } + @router.get("/me") async def read_users_me(current_user: str = Depends(auth.get_current_user)): totp_secret = auth.load_totp_secret() diff --git a/dashboard/docker-compose.yml b/dashboard/docker-compose.yml index b0e2c85..f128876 100644 --- a/dashboard/docker-compose.yml +++ b/dashboard/docker-compose.yml @@ -35,6 +35,7 @@ services: - VPS_SSH_HOST=158.101.140.85 - VPS_SSH_USER=jimmyg - SECRET_KEY=${SECRET_KEY} + - ADMIN_USER=jimmy - ADMIN_PASSWORD_HASH=${ADMIN_PASSWORD_HASH} - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-} - TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-} diff --git a/dashboard/frontend/src/App.svelte b/dashboard/frontend/src/App.svelte index 4c263f1..239fc08 100644 --- a/dashboard/frontend/src/App.svelte +++ b/dashboard/frontend/src/App.svelte @@ -28,7 +28,22 @@ document.documentElement.classList.remove('dark'); } - // Auth check + // Try proxy auth first (Authelia forward-auth sets Remote-User header) + try { + const proxyRes = await fetch("/api/auth/proxy"); + if (proxyRes.ok) { + const data = await proxyRes.json(); + setToken(data.access_token); + setRefreshToken(data.refresh_token); + authorized = true; + loading = false; + return; + } + } catch (e) { + // Proxy auth not available, fall through to regular auth + } + + // Regular token auth check const token = getToken(); if (!token) { loading = false; diff --git a/dashboard/frontend/src/components/Sidebar.svelte b/dashboard/frontend/src/components/Sidebar.svelte index 5e338b0..6608ebc 100644 --- a/dashboard/frontend/src/components/Sidebar.svelte +++ b/dashboard/frontend/src/components/Sidebar.svelte @@ -32,6 +32,7 @@ { label: "Gitea Web", port: 3300, icon: "git", external: true }, { label: "Stirling PDF", port: 8030, icon: "pdf", external: true }, { label: "Vaultwarden", port: 8222, icon: "lock", external: true }, + { label: "User Management", remoteHref: "https://ldap.jimmygan.com:8443", icon: "users", external: true }, { label: "n8n", remoteHref: "https://n8n.jimmygan.com:8443", icon: "n8n", external: true }, { label: "Speedtest", port: 8080, icon: "speedtest", external: true }, ]; @@ -144,6 +145,8 @@ {:else if item.icon === "speedtest"} + {:else if item.icon === "users"} + {:else if item.icon === "n8n"} {/if} diff --git a/dashboard/frontend/src/routes/ChatSummary.svelte b/dashboard/frontend/src/routes/ChatSummary.svelte index 6f629d9..8b56956 100644 --- a/dashboard/frontend/src/routes/ChatSummary.svelte +++ b/dashboard/frontend/src/routes/ChatSummary.svelte @@ -55,6 +55,20 @@ triggering = false; } } + + function markdownToHtml(md) { + if (!md) return ""; + return md + .replace(/&/g, "&").replace(//g, ">") + .replace(/^### (.+)$/gm, '

$1

') + .replace(/^## (.+)$/gm, '

$1

') + .replace(/^# (.+)$/gm, '

$1

') + .replace(/\*\*(.+?)\*\*/g, '$1') + .replace(/\*(.+?)\*/g, '$1') + .replace(/^- (.+)$/gm, '
  • $1
  • ') + .replace(/\n{2,}/g, '

    ') + .replace(/\n/g, '
    '); + }
    @@ -107,19 +121,3 @@ {/if} {/if}
    - - diff --git a/tmp_remote/authelia_docker_compose.yml b/tmp_remote/authelia_docker_compose.yml new file mode 100755 index 0000000..d2b1ccd --- /dev/null +++ b/tmp_remote/authelia_docker_compose.yml @@ -0,0 +1,16 @@ +services: + authelia: + image: authelia/authelia:latest + container_name: authelia + restart: unless-stopped + ports: + - "9092:9091" + volumes: + - /volume1/docker/authelia/config:/config + environment: + - TZ=Asia/Shanghai + logging: + driver: json-file + options: + max-size: "10m" + max-file: "3" diff --git a/tmp_remote/configuration.yml b/tmp_remote/configuration.yml new file mode 100644 index 0000000..3b43bef --- /dev/null +++ b/tmp_remote/configuration.yml @@ -0,0 +1,71 @@ +theme: auto +default_2fa_method: totp + +server: + address: 'tcp://0.0.0.0:9092' + +log: + level: info + +totp: + issuer: nas.jimmygan.com + period: 30 + skew: 1 + +webauthn: + disable: false + display_name: NAS Auth + attestation_conveyance_preference: indirect + user_verification: preferred + timeout: 60s + +authentication_backend: + ldap: + implementation: custom + address: 'ldap://localhost:3890' + timeout: 5s + start_tls: false + base_dn: 'dc=jimmygan,dc=com' + additional_users_dn: 'ou=people' + users_filter: '(&({username_attribute}={input})(objectClass=person))' + additional_groups_dn: 'ou=groups' + groups_filter: '(member={dn})' + user: 'uid=admin,ou=people,dc=jimmygan,dc=com' + password: '5jb6+s69t+r+OmZbizEWJA==' + attributes: + display_name: displayName + mail: mail + member_of: memberOf + group_name: cn + +access_control: + default_policy: two_factor + rules: + - domain: ldap.jimmygan.com + policy: two_factor + +session: + secret: jcpCs/bUYjC85jBDLa3jwgZfC4WyIyjS87LsvO2l3jY= + expiration: 1h + inactivity: 5m + remember_me: 1M + cookies: + - domain: jimmygan.com + authelia_url: https://auth.jimmygan.com:8443 + +storage: + encryption_key: RPXltPeEWip9kJRoDRQOcUF3egeVCluOjma1TpeYbeo= + local: + path: /config/db.sqlite3 + +notifier: + smtp: + address: 'smtp://smtp.gmail.com:587' + username: 'zjgump@gmail.com' + password: 'lkykzvfrubsgvqfv' + sender: 'NAS Auth ' + subject: '[NAS Auth] {title}' + +identity_validation: + reset_password: + jwt_secret: HDty02r/yVwbWavqM+F0ChCgvgWE34XM1mzNFPzOrWY=