Enroll Passkey PRF key on first login recovery phase
This commit is contained in:
@@ -147,6 +147,7 @@ export interface LoginResult {
|
|||||||
encryptedMasterKeyRecTag: string
|
encryptedMasterKeyRecTag: string
|
||||||
userId: string
|
userId: string
|
||||||
username: string
|
username: string
|
||||||
|
prfFirst?: ArrayBuffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +232,8 @@ export async function loginUser(username?: string): Promise<LoginResult> {
|
|||||||
encryptedMasterKeyRecIv: result.encryptedMasterKeyRecIv,
|
encryptedMasterKeyRecIv: result.encryptedMasterKeyRecIv,
|
||||||
encryptedMasterKeyRecTag: result.encryptedMasterKeyRecTag,
|
encryptedMasterKeyRecTag: result.encryptedMasterKeyRecTag,
|
||||||
userId: result.userId,
|
userId: result.userId,
|
||||||
username: resolvedUsername
|
username: resolvedUsername,
|
||||||
|
prfFirst: prfResults?.results?.first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +247,7 @@ export async function completeLoginWithRecovery(
|
|||||||
encryptedMasterKeyRecIv: string
|
encryptedMasterKeyRecIv: string
|
||||||
encryptedMasterKeyRecTag: string
|
encryptedMasterKeyRecTag: string
|
||||||
userId: string
|
userId: string
|
||||||
|
prfFirst?: ArrayBuffer
|
||||||
}
|
}
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
@@ -255,6 +258,32 @@ export async function completeLoginWithRecovery(
|
|||||||
encryptedPayloads.encryptedMasterKeyRecTag,
|
encryptedPayloads.encryptedMasterKeyRecTag,
|
||||||
recoveryKey
|
recoveryKey
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// If PRF results are available from the login challenge, enroll them now
|
||||||
|
if (encryptedPayloads.prfFirst) {
|
||||||
|
try {
|
||||||
|
const prfKey = await deriveKeyFromPrf(encryptedPayloads.prfFirst)
|
||||||
|
const encryptedPrf = await encryptBuffer(decryptedMaster, prfKey)
|
||||||
|
const enrollRes = await fetch(`${API_BASE}/enroll-prf`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-User-Id': encryptedPayloads.userId
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
encryptedMasterKeyPrf: encryptedPrf.ciphertext,
|
||||||
|
encryptedMasterKeyPrfIv: encryptedPrf.iv,
|
||||||
|
encryptedMasterKeyPrfTag: encryptedPrf.tag
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (!enrollRes.ok) {
|
||||||
|
console.warn('Server rejected PRF enrollment')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to encrypt/enroll master key with PRF key:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setActiveMasterKey(decryptedMaster)
|
setActiveMasterKey(decryptedMaster)
|
||||||
localStorage.setItem('active_username', username)
|
localStorage.setItem('active_username', username)
|
||||||
localStorage.setItem('active_userid', encryptedPayloads.userId)
|
localStorage.setItem('active_userid', encryptedPayloads.userId)
|
||||||
|
|||||||
@@ -253,4 +253,41 @@ router.delete('/delete-account', async (req: any, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 6. Enroll PRF encrypted master key
|
||||||
|
router.post('/enroll-prf', async (req: any, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.headers['x-user-id']
|
||||||
|
if (!userId) {
|
||||||
|
return res.status(401).json({ error: 'Unauthorized: X-User-Id header missing' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const { encryptedMasterKeyPrf, encryptedMasterKeyPrfIv, encryptedMasterKeyPrfTag } = req.body
|
||||||
|
if (!encryptedMasterKeyPrf || !encryptedMasterKeyPrfIv || !encryptedMasterKeyPrfTag) {
|
||||||
|
return res.status(400).json({ error: 'Missing required PRF key fields' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof encryptedMasterKeyPrf !== 'string' ||
|
||||||
|
typeof encryptedMasterKeyPrfIv !== 'string' ||
|
||||||
|
typeof encryptedMasterKeyPrfTag !== 'string'
|
||||||
|
) {
|
||||||
|
return res.status(400).json({ error: 'Invalid PRF key fields format' })
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: userId },
|
||||||
|
data: {
|
||||||
|
encryptedMasterKeyPrf,
|
||||||
|
encryptedMasterKeyPrfIv,
|
||||||
|
encryptedMasterKeyPrfTag
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return res.json({ success: true })
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error enrolling PRF key:', error)
|
||||||
|
return res.status(500).json({ error: error.message || 'Internal server error' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
Reference in New Issue
Block a user