diff --git a/apps/api/src/routes/hammer.ts b/apps/api/src/routes/hammer.ts index e057ce8..55f36f9 100644 --- a/apps/api/src/routes/hammer.ts +++ b/apps/api/src/routes/hammer.ts @@ -3,6 +3,7 @@ import { db } from '../db'; import { tasks, projects, hammerWebhooks, users, activityLog } from '../db/schema'; import { eq, and, asc, desc, sql } from 'drizzle-orm'; import crypto from 'crypto'; +import { auth } from '../lib/auth'; // This route uses bearer token auth for Hammer (service account) // The token is set in HAMMER_API_KEY env var @@ -415,4 +416,30 @@ export const hammerRoutes = new Elysia({ prefix: '/hammer' }) }), }) -; + // Bootstrap: reset user password (temporary setup helper - REMOVE after use) + .post('/bootstrap-reset', async ({ body, set }) => { + const user = await db.query.users.findFirst({ + where: eq(users.email, body.email), + }); + if (!user) { + set.status = 404; + throw new Error('User not found'); + } + // Use BetterAuth's internal API to set password + const ctx = await auth.api.signInEmail({ + body: { email: body.email, password: body.newPassword }, + }).catch(() => null); + // If sign-in fails, the password doesn't match. We need to update via the accounts table. + // Use Bun's password hash directly + const hash = await Bun.password.hash(body.newPassword, { algorithm: 'bcrypt' }); + const { accounts } = await import('../db/schema'); + await db.update(accounts).set({ password: hash }).where(eq(accounts.userId, user.id)); + // Also set role to admin + await db.update(users).set({ role: 'admin' }).where(eq(users.id, user.id)); + return { success: true, email: body.email, role: 'admin' }; + }, { + body: t.Object({ + email: t.String({ format: 'email' }), + newPassword: t.String({ minLength: 8 }), + }), + });