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:
parent
99b5187a33
commit
1c79132e22
@ -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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user