Move the whole app under /auth/, fix static build.
This commit is contained in:
parent
7665044032
commit
f9f263171b
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ dist/
|
|||||||
*.lock
|
*.lock
|
||||||
*.db
|
*.db
|
||||||
server-secret.bin
|
server-secret.bin
|
||||||
|
/passkeyauth/frontend-static
|
||||||
|
Binary file not shown.
@ -2,9 +2,9 @@
|
|||||||
<html lang="">
|
<html lang="">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<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">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Vite App</title>
|
<title>Passkey Authentication</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^6.0.0",
|
"@vitejs/plugin-vue": "^6.0.0",
|
||||||
"vite": "^7.0.4",
|
"vite": "^7.0.4"
|
||||||
"vite-plugin-vue-devtools": "^7.7.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
frontend/src/assets/icon.webp
Normal file
BIN
frontend/src/assets/icon.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
@ -1,6 +1,5 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { registerUser, authenticateUser, registerWithToken } from '@/utils/passkey'
|
import { registerUser, authenticateUser, registerWithToken } from '@/utils/passkey'
|
||||||
import aWebSocket from '@/utils/awaitable-websocket'
|
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore('auth', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@ -102,18 +101,6 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
this.isLoading = false
|
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) {
|
async deleteCredential(credentialId) {
|
||||||
const response = await fetch('/auth/delete-credential', {
|
const response = await fetch('/auth/delete-credential', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -138,24 +125,5 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
this.currentCredentials = []
|
this.currentCredentials = []
|
||||||
this.aaguidInfo = {}
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -22,7 +22,7 @@ export async function registerCredential() {
|
|||||||
return register('/auth/ws/add_credential')
|
return register('/auth/ws/add_credential')
|
||||||
}
|
}
|
||||||
export async function registerWithToken(token) {
|
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() {
|
export async function authenticateUser() {
|
||||||
|
@ -2,19 +2,18 @@ import { fileURLToPath, URL } from 'node:url'
|
|||||||
|
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
vueDevTools(),
|
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
base: '/auth/',
|
||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
@ -26,7 +25,7 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: '../static/dist',
|
outDir: '../passkeyauth/frontend-static',
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
assetsDir: 'assets'
|
assetsDir: 'assets'
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,7 @@ from .passkey import Passkey
|
|||||||
from .reset_handlers import create_device_addition_link, validate_device_addition_token
|
from .reset_handlers import create_device_addition_link, validate_device_addition_token
|
||||||
from .session_manager import get_user_from_cookie_string
|
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(
|
passkey = Passkey(
|
||||||
rp_id="localhost",
|
rp_id="localhost",
|
||||||
@ -213,7 +212,7 @@ async def websocket_authenticate(ws: WebSocket):
|
|||||||
await ws.accept()
|
await ws.accept()
|
||||||
origin = ws.headers.get("origin")
|
origin = ws.headers.get("origin")
|
||||||
try:
|
try:
|
||||||
options, challenge = passkey.auth_generate_options(origin=origin)
|
options, challenge = passkey.auth_generate_options()
|
||||||
await ws.send_json(options)
|
await ws.send_json(options)
|
||||||
# Wait for the client to use his authenticator to authenticate
|
# Wait for the client to use his authenticator to authenticate
|
||||||
credential = passkey.auth_parse(await ws.receive_json())
|
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
|
# 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
|
# Catch-all route for SPA - serve index.html for all non-API routes
|
||||||
@app.get("/{path:path}")
|
@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)"""
|
"""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")
|
return FileResponse(STATIC_DIR / "index.html")
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user