Implement Workstream F1: me.get and me.setupProfile procedures
- Add me.get procedure returning user profile with needsSetup flag - Add me.setupProfile procedure for initial profile setup after signup - Add nonEmptyString/optionalString schema helpers with tests - Use Web Crypto API (SubtleCrypto) for Cloudflare Workers compatibility - Use @formatjs/intl-durationformat for duration formatting - Remove node:crypto dependency from crypto utilities Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
|
||||
/**
|
||||
* Hash a token with SHA-256 for storage in database
|
||||
* Never store raw tokens - always hash first
|
||||
* Uses Web Crypto API for Cloudflare Workers compatibility
|
||||
*/
|
||||
export const hashToken = (token: string): string => {
|
||||
return createHash("sha256").update(token).digest("hex");
|
||||
export const hashToken = async (token: string): Promise<string> => {
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(token);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||
const hashArray = new Uint8Array(hashBuffer);
|
||||
return Array.from(hashArray)
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -25,9 +30,14 @@ export const generateDeviceFingerprint = (): string => {
|
||||
/**
|
||||
* Generate a secure random token for email verification, password reset, etc.
|
||||
* Uses 32 bytes (256 bits) of entropy
|
||||
* Uses Web Crypto API for Cloudflare Workers compatibility
|
||||
*/
|
||||
export const generateSecureToken = (): string => {
|
||||
return randomBytes(32).toString("hex");
|
||||
const bytes = new Uint8Array(32);
|
||||
crypto.getRandomValues(bytes);
|
||||
return Array.from(bytes)
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user