Nxing/Caddy forward_auth support. Various fixes to bugs created in earlier edits. Vite server needs different base in dev mode, fixed.
This commit is contained in:
		| @@ -31,7 +31,11 @@ const handleLogin = async () => { | |||||||
|     authStore.showMessage('Starting authentication...', 'info') |     authStore.showMessage('Starting authentication...', 'info') | ||||||
|     await authStore.authenticate() |     await authStore.authenticate() | ||||||
|     authStore.showMessage('Authentication successful!', 'success', 2000) |     authStore.showMessage('Authentication successful!', 'success', 2000) | ||||||
|  |     if (location.pathname.startsWith('/auth/')) { | ||||||
|       authStore.currentView = 'profile' |       authStore.currentView = 'profile' | ||||||
|  |     } else { | ||||||
|  |       location.reload() | ||||||
|  |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     authStore.showMessage(`Authentication failed: ${error.message}`, 'error') |     authStore.showMessage(`Authentication failed: ${error.message}`, 'error') | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|       <form @submit.prevent="handleRegister"> |       <form @submit.prevent="handleRegister"> | ||||||
|         <input |         <input | ||||||
|           type="text" |           type="text" | ||||||
|           v-model="username" |           v-model="user_name" | ||||||
|           placeholder="Enter username" |           placeholder="Enter username" | ||||||
|           required |           required | ||||||
|           :disabled="authStore.isLoading" |           :disabled="authStore.isLoading" | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|         <button |         <button | ||||||
|           type="submit" |           type="submit" | ||||||
|           class="btn-primary" |           class="btn-primary" | ||||||
|           :disabled="authStore.isLoading || !username.trim()" |           :disabled="authStore.isLoading || !user_name.trim()" | ||||||
|         > |         > | ||||||
|           {{ authStore.isLoading ? 'Registering...' : 'Register Passkey' }} |           {{ authStore.isLoading ? 'Registering...' : 'Register Passkey' }} | ||||||
|         </button> |         </button> | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ export async function register(url, options) { | |||||||
| } | } | ||||||
|  |  | ||||||
| export async function registerUser(user_name) { | export async function registerUser(user_name) { | ||||||
|   return register('/auth/ws/new_user_registration', { user_name }) |   return register('/auth/ws/register_new', { user_name }) | ||||||
| } | } | ||||||
|  |  | ||||||
| export async function registerCredential() { | export async function registerCredential() { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import { defineConfig } from 'vite' | |||||||
| import vue from '@vitejs/plugin-vue' | import vue from '@vitejs/plugin-vue' | ||||||
|  |  | ||||||
| // https://vite.dev/config/ | // https://vite.dev/config/ | ||||||
| export default defineConfig({ | export default defineConfig(({ command, mode }) => ({ | ||||||
|   plugins: [ |   plugins: [ | ||||||
|     vue(), |     vue(), | ||||||
|   ], |   ], | ||||||
| @@ -13,7 +13,7 @@ export default defineConfig({ | |||||||
|       '@': fileURLToPath(new URL('./src', import.meta.url)) |       '@': fileURLToPath(new URL('./src', import.meta.url)) | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   base: '/auth/', |   base: command == 'build' ? '/auth/' : '/', | ||||||
|   server: { |   server: { | ||||||
|     port: 3000, |     port: 3000, | ||||||
|     proxy: { |     proxy: { | ||||||
| @@ -29,4 +29,4 @@ export default defineConfig({ | |||||||
|     emptyOutDir: true, |     emptyOutDir: true, | ||||||
|     assetsDir: 'assets' |     assetsDir: 'assets' | ||||||
|   } |   } | ||||||
| }) | })) | ||||||
|   | |||||||
| @@ -15,11 +15,17 @@ from datetime import datetime | |||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from uuid import UUID, uuid4 | from uuid import UUID, uuid4 | ||||||
|  |  | ||||||
| from fastapi import FastAPI, Request, Response, WebSocket, WebSocketDisconnect | from fastapi import ( | ||||||
|  |     FastAPI, | ||||||
|  |     Request, | ||||||
|  |     Response, | ||||||
|  |     WebSocket, | ||||||
|  |     WebSocketDisconnect, | ||||||
|  | ) | ||||||
| from fastapi import ( | from fastapi import ( | ||||||
|     Path as FastAPIPath, |     Path as FastAPIPath, | ||||||
| ) | ) | ||||||
| from fastapi.responses import FileResponse, RedirectResponse | from fastapi.responses import FileResponse, JSONResponse, RedirectResponse | ||||||
| from fastapi.staticfiles import StaticFiles | from fastapi.staticfiles import StaticFiles | ||||||
| from webauthn.helpers.exceptions import InvalidAuthenticationResponse | from webauthn.helpers.exceptions import InvalidAuthenticationResponse | ||||||
|  |  | ||||||
| @@ -204,7 +210,7 @@ async def register_chat( | |||||||
|     ) |     ) | ||||||
|     await ws.send_json(options) |     await ws.send_json(options) | ||||||
|     response = await ws.receive_json() |     response = await ws.receive_json() | ||||||
|     return passkey.reg_verify(response, challenge, user_id) |     return passkey.reg_verify(response, challenge, user_id, origin=origin) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.websocket("/auth/ws/authenticate") | @app.websocket("/auth/ws/authenticate") | ||||||
| @@ -269,6 +275,27 @@ async def api_validate_token(request: Request): | |||||||
|     return await validate_token(request) |     return await validate_token(request) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.get("/auth/forward-auth") | ||||||
|  | async def forward_authentication(request: Request): | ||||||
|  |     """A verification endpoint to use with Caddy forward_auth or Nginx auth_request.""" | ||||||
|  |     result = await validate_token(request) | ||||||
|  |     if result.get("status") != "success": | ||||||
|  |         # Serve the index.html of the authentication app if not authenticated | ||||||
|  |         return FileResponse( | ||||||
|  |             STATIC_DIR / "index.html", | ||||||
|  |             status_code=401, | ||||||
|  |             headers={"www-authenticate": "PrivateToken"}, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     # If authenticated, return a success response | ||||||
|  |     return JSONResponse( | ||||||
|  |         result, | ||||||
|  |         headers={ | ||||||
|  |             "x-auth-user-id": result["user_id"], | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.post("/auth/logout") | @app.post("/auth/logout") | ||||||
| async def api_logout(response: Response): | async def api_logout(response: Response): | ||||||
|     """Log out the current user by clearing the session cookie.""" |     """Log out the current user by clearing the session cookie.""" | ||||||
| @@ -315,20 +342,6 @@ async def reset_authentication( | |||||||
|     return response |     return response | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.get("/auth/user-info-by-passphrase") |  | ||||||
| async def api_get_user_info_by_passphrase(token: str): |  | ||||||
|     """Get user information using the passphrase.""" |  | ||||||
|     reset_token = await db.get_reset_token(token) |  | ||||||
|     if not reset_token: |  | ||||||
|         return Response(content="Invalid or expired passphrase", status_code=403) |  | ||||||
|  |  | ||||||
|     user = await db.get_user_by_id(reset_token.user_id) |  | ||||||
|     if not user: |  | ||||||
|         return Response(content="User not found", status_code=404) |  | ||||||
|  |  | ||||||
|     return {"user_name": user.user_name} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Serve static files | # Serve static files | ||||||
| app.mount( | app.mount( | ||||||
|     "/auth/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="static assets" |     "/auth/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="static assets" | ||||||
|   | |||||||
| @@ -141,11 +141,10 @@ class Passkey: | |||||||
|             Registration verification result |             Registration verification result | ||||||
|         """ |         """ | ||||||
|         credential = parse_registration_credential_json(response_json) |         credential = parse_registration_credential_json(response_json) | ||||||
|         expected_origin = origin or self.origin |  | ||||||
|         registration = verify_registration_response( |         registration = verify_registration_response( | ||||||
|             credential=credential, |             credential=credential, | ||||||
|             expected_challenge=expected_challenge, |             expected_challenge=expected_challenge, | ||||||
|             expected_origin=expected_origin, |             expected_origin=origin or self.origin, | ||||||
|             expected_rp_id=self.rp_id, |             expected_rp_id=self.rp_id, | ||||||
|         ) |         ) | ||||||
|         return StoredCredential( |         return StoredCredential( | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Leo Vasanko
					Leo Vasanko