feat: fix setup guide download with embedded credentials + profile page regenerate secret
- downloadSetupGuide() now triggers a real file download with bot_id/secret injected - Add POST /api/auth/regenerate-secret endpoint (JWT auth, 3/hour rate limit) - Add "Download Setup Guide" section to BotProfilePage with secret regeneration flow - Old secret immediately invalidated on regeneration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
47bc753f95
commit
cef9f4188f
@@ -486,3 +486,41 @@ authRouter.post('/nostr/session', rateLimit(60_000, 10), async (c) => {
|
||||
bot: botData,
|
||||
})
|
||||
})
|
||||
|
||||
// Regenerate bot secret (requires JWT auth — owner only)
|
||||
authRouter.post('/regenerate-secret', rateLimit(3_600_000, 3), async (c) => {
|
||||
const pubkey = extractPubkeyFromAuth(c.req.header('Authorization'))
|
||||
if (!pubkey) {
|
||||
return c.json({ error: 'Authentication required.' }, 401)
|
||||
}
|
||||
|
||||
const rows = await db.select({
|
||||
id: schema.bots.id,
|
||||
name: schema.bots.name,
|
||||
webhookUrl: schema.bots.webhookUrl,
|
||||
})
|
||||
.from(schema.bots)
|
||||
.where(eq(schema.bots.publicKey, pubkey))
|
||||
.limit(1)
|
||||
|
||||
if (rows.length === 0) {
|
||||
return c.json({ error: 'No bot found for this key.' }, 404)
|
||||
}
|
||||
|
||||
const bot = rows[0]
|
||||
const isHuman = bot.webhookUrl === 'http://human.local/'
|
||||
if (isHuman) {
|
||||
return c.json({ error: 'Human players do not use bot secrets.' }, 400)
|
||||
}
|
||||
|
||||
const secret = randomBytes(32).toString('hex')
|
||||
await db.update(schema.bots)
|
||||
.set({ secretHash: createHash('sha256').update(secret).digest('hex') })
|
||||
.where(eq(schema.bots.id, bot.id))
|
||||
|
||||
return c.json({
|
||||
botId: bot.id,
|
||||
secret,
|
||||
message: 'Secret regenerated. Your old secret no longer works. Save this immediately.',
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user