mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-30 17:50:07 +08:00
de4938e75c
- Add `shares` and `share_recipients` tables to Drizzle schema with indices - Add migration 0010_shares.sql for shares/share_recipients tables - Add `server/lib/password.ts` extracting scrypt hash/verify from auth.ts to eliminate duplicate crypto params across services - Add `server/services/share.ts` implementing full CRUD + atomic counters: createShare, getShareByToken, incrementViews, incrementDownloadsAtomic (atomic SQL UPDATE), listSharesByCreator, revokeShare, cascadeDeleteByMatter - Add `shared/schemas/share.ts` Zod validation schemas - Export Share, ShareKind, ShareRecipient from shared/types - Extend `purge.ts` to cascade-delete shares on matter hard-delete - Add 38 integration tests and CF Workers atomic counter race tests Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
19 lines
866 B
TypeScript
19 lines
866 B
TypeScript
import crypto from 'node:crypto'
|
|
|
|
// node:crypto.scryptSync is native OpenSSL — safe on Cloudflare Workers (nodejs_compat)
|
|
// and avoids the JS-CPU budget issue that the pure-JS @noble/hashes scrypt triggers.
|
|
const SCRYPT_PARAMS = { N: 16384, r: 16, p: 1, maxmem: 128 * 16384 * 16 * 2 }
|
|
|
|
export function hashPassword(password: string): string {
|
|
const salt = crypto.randomBytes(16)
|
|
const key = crypto.scryptSync(password.normalize('NFKC'), salt, 64, SCRYPT_PARAMS)
|
|
return `${salt.toString('hex')}:${key.toString('hex')}`
|
|
}
|
|
|
|
export function verifyPassword(hash: string, plaintext: string): boolean {
|
|
const [saltHex, keyHex] = hash.split(':')
|
|
if (!saltHex || !keyHex) return false
|
|
const key = crypto.scryptSync(plaintext.normalize('NFKC'), Buffer.from(saltHex, 'hex'), 64, SCRYPT_PARAMS)
|
|
return crypto.timingSafeEqual(key, Buffer.from(keyHex, 'hex'))
|
|
}
|