fix(invite-claim): send publicKey + JSON error responses
The /join and OIDC accept pages were calling /api/register/complete without the public key extracted from the WebAuthn attestation. storeCredential writes a credentials row with a NOT NULL public_key column, so the request crashed with an unhandled exception and Hono replied "Internal Server Error" as plain text — the client JSON.parse choked on it. - Extract credential.response.getPublicKey() on the client and include it in the completion payload (both /join and /oidc/accept flows). - Add app.onError to return JSON 500s on /api/* routes so any future crashes produce parseable error bodies instead of cascading into confusing "Unexpected token 'I'" errors in the browser.
This commit is contained in:
parent
0a896f5740
commit
5bb46afe6d
|
|
@ -484,6 +484,18 @@ app.use('*', cors({
|
|||
credentials: true,
|
||||
}));
|
||||
|
||||
// Return JSON for unhandled exceptions on JSON API routes so client-side
|
||||
// `await res.json()` doesn't choke on plain-text "Internal Server Error".
|
||||
app.onError((err, c) => {
|
||||
const path = c.req.path;
|
||||
console.error(`EncryptID: ${c.req.method} ${path} failed:`, err);
|
||||
const wantsJson = path.startsWith('/api/') || (c.req.header('accept') || '').includes('application/json');
|
||||
if (wantsJson) {
|
||||
return c.json({ error: 'Internal server error', detail: err.message }, 500);
|
||||
}
|
||||
return c.text('Internal Server Error', 500);
|
||||
});
|
||||
|
||||
// /api/internal/* is for service-to-service calls over the Docker network only.
|
||||
// Traefik adds X-Forwarded-For for any request arriving through the public edge
|
||||
// (CF tunnel, direct HTTPS). Direct container-to-container fetches do not set it.
|
||||
|
|
@ -6385,6 +6397,11 @@ function joinPage(token: string): string {
|
|||
.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');
|
||||
const clientDataJSON = btoa(String.fromCharCode(...new Uint8Array(credential.response.clientDataJSON)))
|
||||
.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');
|
||||
const publicKeyBytes = credential.response.getPublicKey ? credential.response.getPublicKey() : null;
|
||||
const publicKey = publicKeyBytes
|
||||
? btoa(String.fromCharCode(...new Uint8Array(publicKeyBytes)))
|
||||
.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')
|
||||
: '';
|
||||
|
||||
const completeRes = await fetch('/api/register/complete', {
|
||||
method: 'POST',
|
||||
|
|
@ -6396,6 +6413,7 @@ function joinPage(token: string): string {
|
|||
deviceName: detectDeviceName(),
|
||||
credential: {
|
||||
credentialId,
|
||||
publicKey,
|
||||
attestationObject,
|
||||
clientDataJSON,
|
||||
transports: credential.response.getTransports ? credential.response.getTransports() : [],
|
||||
|
|
@ -6728,6 +6746,7 @@ function oidcAcceptPage(token: string): string {
|
|||
});
|
||||
|
||||
showStatus('Completing registration...');
|
||||
const publicKeyBytes = credential.response.getPublicKey ? credential.response.getPublicKey() : null;
|
||||
const completeRes = await fetch('/api/register/complete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
|
@ -6738,6 +6757,7 @@ function oidcAcceptPage(token: string): string {
|
|||
deviceName: detectDeviceName(),
|
||||
credential: {
|
||||
credentialId: toB64url(credential.rawId),
|
||||
publicKey: publicKeyBytes ? toB64url(publicKeyBytes) : '',
|
||||
attestationObject: toB64url(credential.response.attestationObject),
|
||||
clientDataJSON: toB64url(credential.response.clientDataJSON),
|
||||
transports: credential.response.getTransports ? credential.response.getTransports() : [],
|
||||
|
|
|
|||
Loading…
Reference in New Issue