Move the whole app under /auth/, fix static build.

This commit is contained in:
Leo Vasanko 2025-07-13 14:03:15 -06:00
parent 7665044032
commit f9f263171b
9 changed files with 22 additions and 46 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ dist/
*.lock
*.db
server-secret.bin
/passkeyauth/frontend-static

Binary file not shown.

View File

@ -2,9 +2,9 @@
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/src/assets/icon.webp">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title>Passkey Authentication</title>
</head>
<body>
<div id="app"></div>

View File

@ -16,7 +16,6 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.0",
"vite": "^7.0.4",
"vite-plugin-vue-devtools": "^7.7.7"
"vite": "^7.0.4"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@ -1,6 +1,5 @@
import { defineStore } from 'pinia'
import { registerUser, authenticateUser, registerWithToken } from '@/utils/passkey'
import aWebSocket from '@/utils/awaitable-websocket'
export const useAuthStore = defineStore('auth', {
state: () => ({
@ -102,18 +101,6 @@ export const useAuthStore = defineStore('auth', {
this.isLoading = false
}
},
async addNewCredential() {
this.isLoading = true;
try {
const result = await registerWithToken()
await this.loadCredentials()
return result;
} catch (error) {
throw new Error(`Failed to add new credential: ${error.message}`)
} finally {
this.isLoading = false
}
},
async deleteCredential(credentialId) {
const response = await fetch('/auth/delete-credential', {
method: 'POST',
@ -138,24 +125,5 @@ export const useAuthStore = defineStore('auth', {
this.currentCredentials = []
this.aaguidInfo = {}
},
async checkResetCookieAndRegister() {
const passphrase = getCookie('reset')
if (passphrase) {
// Abandon existing session
await fetch('/auth/logout', { method: 'POST', credentials: 'include' })
// Register additional token for the user
try {
const result = await registerUserFromCookie()
await this.setSessionCookie(result.session_token)
this.currentUser = {
user_id: result.user_id,
user_name: result.user_name,
}
} catch (error) {
console.error('Failed to register additional token:', error)
}
}
},
}
})

View File

@ -22,7 +22,7 @@ export async function registerCredential() {
return register('/auth/ws/add_credential')
}
export async function registerWithToken(token) {
return register('/auth/ws/add_device_credential', {token})
return register('/auth/ws/add_device_credential', { token })
}
export async function authenticateUser() {

View File

@ -2,19 +2,18 @@ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
base: '/auth/',
server: {
port: 3000,
proxy: {
@ -26,7 +25,7 @@ export default defineConfig({
}
},
build: {
outDir: '../static/dist',
outDir: '../passkeyauth/frontend-static',
emptyOutDir: true,
assetsDir: 'assets'
}

View File

@ -39,8 +39,7 @@ from .passkey import Passkey
from .reset_handlers import create_device_addition_link, validate_device_addition_token
from .session_manager import get_user_from_cookie_string
STATIC_DIR = Path(__file__).parent.parent / "static"
STATIC_DIR = Path(__file__).parent / "frontend-static"
passkey = Passkey(
rp_id="localhost",
@ -213,7 +212,7 @@ async def websocket_authenticate(ws: WebSocket):
await ws.accept()
origin = ws.headers.get("origin")
try:
options, challenge = passkey.auth_generate_options(origin=origin)
options, challenge = passkey.auth_generate_options()
await ws.send_json(options)
# Wait for the client to use his authenticator to authenticate
credential = passkey.auth_parse(await ws.receive_json())
@ -331,13 +330,23 @@ async def api_get_user_info_by_passphrase(token: str):
# Serve static files
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
app.mount(
"/auth/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="static assets"
)
@app.get("/auth")
async def redirect_to_index():
"""Serve the main authentication app."""
return FileResponse(STATIC_DIR / "index.html")
# Catch-all route for SPA - serve index.html for all non-API routes
@app.get("/{path:path}")
async def spa_handler(path: str):
async def spa_handler(request: Request, path: str):
"""Serve the Vue SPA for all routes (except API and static)"""
if "text/html" not in request.headers.get("accept", ""):
return Response(content="Not Found", status_code=404)
return FileResponse(STATIC_DIR / "index.html")