// POST /register — API Key 發放 // email → HMAC-SHA256(email, ENCRYPTION_KEY) → api_key (ak_ 前綴) // 同一個 email 永遠得到相同的 Key,無需資料庫 import { Hono } from 'hono'; import type { Bindings } from '../types'; export const registerRouter = new Hono<{ Bindings: Bindings }>(); registerRouter.post('/register', async (c) => { let email: string; try { const body = await c.req.json() as { email?: string }; email = (body.email ?? '').trim().toLowerCase(); } catch { return c.json({ success: false, error: 'request body 必須為 JSON' }, 400); } if (!email || !email.includes('@')) { return c.json({ success: false, error: 'email 格式不正確' }, 400); } const encryptionKey = c.env.ENCRYPTION_KEY; if (!encryptionKey || encryptionKey.length < 32) { return c.json({ success: false, error: 'server configuration error' }, 500); } // HMAC-SHA256(email, ENCRYPTION_KEY) → hex → 取前 32 字元 → ak_ 前綴 const keyData = new TextEncoder().encode(encryptionKey.slice(0, 32)); const msgData = new TextEncoder().encode(email); const cryptoKey = await crypto.subtle.importKey( 'raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); const sig = await crypto.subtle.sign('HMAC', cryptoKey, msgData); const hex = Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, '0')).join(''); const apiKey = 'ak_' + hex.slice(0, 32); return c.json({ success: true, api_key: apiKey, encryption_key: encryptionKey, // 用戶需要此 key 才能加密上傳 credential email, message: 'API Key 已發放,請妥善保存。相同 email 永遠得到相同的 Key。', }); });