Implement auth procedures with code review fixes

Add complete auth backend (Workstream D):
- Auth middleware for session/API key authentication
- Signup with password or passkey (WebAuthn)
- Login flow with device trust and email confirmation
- Password reset and email verification
- Session management and logout

Utilities created:
- cookies.ts: Cookie helpers and configuration
- crypto.ts: Token generation and hashing
- password.ts: zxcvbn validation, argon2id hashing
- geo.ts: IP/location extraction from headers
- email.ts: Stubbed email sending
- session.ts: Session creation and device trust

Code review improvements applied:
- Use ORPCError instead of Error in procedures
- Add ast-grep rule to enforce ORPCError usage
- Remove error info leakage (generic messages)
- Optimize N+1 query with JOIN in login-password
- Extract signupWithPassword/signupWithPasskey for testability
- Add 15-minute WebAuthn challenge expiry check
- Strengthen CookieOptions type definitions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
RevIQ
2026-01-09 15:19:15 +08:00
parent 8de88472b1
commit 829d365e80
24 changed files with 1739 additions and 47 deletions

View File

@@ -0,0 +1,46 @@
/**
* Email sending utilities (stubbed for now)
* Will be implemented in Workstream G with actual Postmark integration
*/
/**
* Get the base URL for email links
* Read at function call time to allow environment variable changes
*/
const getBaseUrl = (): string => Bun.env.APP_URL ?? "http://localhost:6827";
/**
* Send verification email to user
*/
export async function sendVerificationEmail(
email: string,
token: string,
): Promise<void> {
const url = `${getBaseUrl()}/auth/verify?token=${token}`;
console.log(`[EMAIL STUB] Verification email to ${email}`);
console.log(`[EMAIL STUB] Verify link: ${url}`);
}
/**
* Send login confirmation email (for untrusted device flow)
*/
export async function sendLoginConfirmationEmail(
email: string,
token: string,
): Promise<void> {
const url = `${getBaseUrl()}/auth/confirm?token=${token}`;
console.log(`[EMAIL STUB] Login confirmation to ${email}`);
console.log(`[EMAIL STUB] Confirm link: ${url}`);
}
/**
* Send password reset email
*/
export async function sendPasswordResetEmail(
email: string,
token: string,
): Promise<void> {
const url = `${getBaseUrl()}/auth/reset-password?token=${token}`;
console.log(`[EMAIL STUB] Password reset to ${email}`);
console.log(`[EMAIL STUB] Reset link: ${url}`);
}