diff --git a/src/encryptid/db.ts b/src/encryptid/db.ts index 28998183..426f7cfc 100644 --- a/src/encryptid/db.ts +++ b/src/encryptid/db.ts @@ -84,13 +84,13 @@ export async function getUserByUsername(username: string) { // CREDENTIAL OPERATIONS // ============================================================================ -export async function storeCredential(cred: StoredCredential, did?: string): Promise { +export async function storeCredential(cred: StoredCredential, did?: string, label?: string): Promise { // Ensure user exists first (with display name + DID so they're never NULL) // If a proper DID is provided (e.g. from PRF key derivation), use it; otherwise omit await createUser(cred.userId, cred.username, cred.username, did || undefined); await sql` - INSERT INTO credentials (credential_id, user_id, public_key, counter, transports, created_at, rp_id) + INSERT INTO credentials (credential_id, user_id, public_key, counter, transports, created_at, rp_id, label) VALUES ( ${cred.credentialId}, ${cred.userId}, @@ -98,7 +98,8 @@ export async function storeCredential(cred: StoredCredential, did?: string): Pro ${cred.counter}, ${cred.transports || null}, ${new Date(cred.createdAt)}, - ${cred.rpId || 'rspace.online'} + ${cred.rpId || 'rspace.online'}, + ${label || null} ) `; } diff --git a/src/encryptid/server.ts b/src/encryptid/server.ts index 3844f080..e43ad65b 100644 --- a/src/encryptid/server.ts +++ b/src/encryptid/server.ts @@ -600,7 +600,7 @@ app.post('/api/register/complete', async (c) => { if (!body) { return c.json({ error: 'Invalid request body' }, 400); } - const { challenge, credential, userId, username, email, clientDid, eoaAddress } = body; + const { challenge, credential, userId, username, email, clientDid, eoaAddress, deviceName } = body; if (!userId || !credential || !username) { return c.json({ error: 'Missing required fields: userId, credential, username' }, 400); @@ -644,7 +644,8 @@ app.post('/api/register/complete', async (c) => { transports: credential.transports, rpId, }; - await storeCredential(storedCredential, did); + const credLabel = (typeof deviceName === 'string' && deviceName.trim()) ? deviceName.trim().slice(0, 100) : undefined; + await storeCredential(storedCredential, did, credLabel); // Store wallet address if provided (from PRF-derived EOA) if (eoaAddress && typeof eoaAddress === 'string' && eoaAddress.startsWith('0x')) { @@ -1869,7 +1870,7 @@ app.post('/api/account/device/complete', async (c) => { const claims = await verifyTokenFromRequest(c.req.header('Authorization')); if (!claims) return c.json({ error: 'Unauthorized' }, 401); - const { challenge, credential } = await c.req.json(); + const { challenge, credential, deviceName } = await c.req.json(); if (!challenge || !credential?.credentialId) { return c.json({ error: 'Challenge and credential required' }, 400); } @@ -1891,6 +1892,7 @@ app.post('/api/account/device/complete', async (c) => { if (!user) return c.json({ error: 'User not found' }, 404); const rpId = resolveRpId(c); + const devLabel = (typeof deviceName === 'string' && deviceName.trim()) ? deviceName.trim().slice(0, 100) : undefined; await storeCredential({ credentialId: credential.credentialId, publicKey: credential.publicKey || '', @@ -1900,7 +1902,7 @@ app.post('/api/account/device/complete', async (c) => { createdAt: Date.now(), transports: credential.transports || [], rpId, - }); + }, undefined, devLabel); console.log('EncryptID: Additional device registered for', user.username); return c.json({ success: true }); @@ -2336,6 +2338,25 @@ app.get('/recover', (c) => {