码桶
发现社区成员的开源项目
credentials.js2.2 KB
// GET /api/passkey/credentials — list user's passkeys
// DELETE /api/passkey/credentials?id=... — delete a passkey
// Requires authentication (JWT).
export async function onRequestGet(context) {
const { env } = context;
const kv = env.CF_DNS_KV;
const user = context.data.user;
if (!kv || !user || !user.username) {
return new Response(JSON.stringify({ error: 'Authentication required.' }), {
status: 401, headers: { 'Content-Type': 'application/json' }
});
}
const credsJson = await kv.get(`PASSKEY_CREDS:${user.username}`);
const creds = credsJson ? JSON.parse(credsJson) : [];
// Return only safe fields (no publicKey)
const safeList = creds.map(c => ({
id: c.credentialId,
name: c.name || 'Passkey',
createdAt: c.createdAt,
}));
return new Response(JSON.stringify({ credentials: safeList }), {
headers: { 'Content-Type': 'application/json' }
});
}
export async function onRequestDelete(context) {
const { request, env } = context;
const kv = env.CF_DNS_KV;
const user = context.data.user;
if (!kv || !user || !user.username) {
return new Response(JSON.stringify({ error: 'Authentication required.' }), {
status: 401, headers: { 'Content-Type': 'application/json' }
});
}
const url = new URL(request.url);
const credId = url.searchParams.get('id');
if (!credId) {
return new Response(JSON.stringify({ error: 'Credential ID is required.' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
const credsJson = await kv.get(`PASSKEY_CREDS:${user.username}`);
let creds = credsJson ? JSON.parse(credsJson) : [];
const before = creds.length;
creds = creds.filter(c => c.credentialId !== credId);
if (creds.length === before) {
return new Response(JSON.stringify({ error: 'Credential not found.' }), {
status: 404, headers: { 'Content-Type': 'application/json' }
});
}
await kv.put(`PASSKEY_CREDS:${user.username}`, JSON.stringify(creds));
return new Response(JSON.stringify({ success: true, remaining: creds.length }), {
headers: { 'Content-Type': 'application/json' }
});
}