test(09-02): add failing test for GET /api/auth/me (BOT-01)

Covers missing / malformed / forged / blacklisted / unregistered / valid
JWT cases for the JWT-only identity route that replaces the bare-pubkey
auto-restore path. Route does not exist yet — 6/7 fail as expected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-07-30 22:03:18 -04:00
co-authored by Claude Fable 5
parent bbc3c7acff
commit e824f4ca7f
+116
View File
@@ -0,0 +1,116 @@
import { describe, it, expect } from 'vitest'
import { Hono } from 'hono'
import { authRouter } from './auth.js'
import { generateSecretKey, getPublicKey } from 'nostr-tools'
import { createJwt, blacklistJwt } from '../middleware/jwt.js'
import { db, schema } from '../db/index.js'
import { createHash, randomBytes } from 'crypto'
import { nanoid } from 'nanoid'
const app = new Hono()
app.route('/api/auth', authRouter)
async function seedBot(pubkey: string, overrides: Partial<typeof schema.bots.$inferInsert> = {}) {
const id = overrides.id || nanoid(12)
const secret = randomBytes(32).toString('hex')
await db.insert(schema.bots).values({
id,
name: overrides.name || `t${Date.now().toString(36).slice(-8)}`,
webhookUrl: overrides.webhookUrl || 'http://poll.local/',
avatarSeed: overrides.avatarSeed || 'seed',
archetype: overrides.archetype || 'standard',
secretHash: createHash('sha256').update(secret).digest('hex'),
publicKey: pubkey,
profilePicUrl: overrides.profilePicUrl ?? null,
customization: overrides.customization ?? null,
createdAt: overrides.createdAt || new Date().toISOString(),
})
return id
}
describe('GET /api/auth/me', () => {
it('rejects when no Authorization header is present', async () => {
const res = await app.request('/api/auth/me')
expect(res.status).toBe(401)
const body = await res.json() as { error: string }
expect(body.error).toBeDefined()
})
it('rejects a malformed / garbage Bearer value', async () => {
const res = await app.request('/api/auth/me', {
headers: { Authorization: 'Bearer not-a-real-jwt' },
})
expect(res.status).toBe(401)
const body = await res.json() as { error: string }
expect(body.error).toBeDefined()
})
it('rejects a token whose signature does not verify', async () => {
const pk = getPublicKey(generateSecretKey())
const token = createJwt(pk)
const parts = token.split('.')
// tamper one character of the signature segment
const tamperedSig = (parts[2][0] === 'a' ? 'b' : 'a') + parts[2].slice(1)
const tampered = `${parts[0]}.${parts[1]}.${tamperedSig}`
const res = await app.request('/api/auth/me', {
headers: { Authorization: `Bearer ${tampered}` },
})
expect(res.status).toBe(401)
})
it('rejects a blacklisted token', async () => {
const pk = getPublicKey(generateSecretKey())
const token = createJwt(pk)
blacklistJwt(token)
const res = await app.request('/api/auth/me', {
headers: { Authorization: `Bearer ${token}` },
})
expect(res.status).toBe(401)
})
it('returns exists:false for a valid token with no bot row', async () => {
const pk = getPublicKey(generateSecretKey())
const token = createJwt(pk)
const res = await app.request('/api/auth/me', {
headers: { Authorization: `Bearer ${token}` },
})
expect(res.status).toBe(200)
const body = await res.json() as { exists: boolean }
expect(body.exists).toBe(false)
})
it('returns exists:true with the bot for a valid token owning a bot row', async () => {
const pk = getPublicKey(generateSecretKey())
const name = `me${Date.now().toString(36).slice(-8)}`
const botId = await seedBot(pk, { name })
const token = createJwt(pk, botId)
const res = await app.request('/api/auth/me', {
headers: { Authorization: `Bearer ${token}` },
})
expect(res.status).toBe(200)
const body = await res.json() as { exists: boolean; bot: { id: string; name: string; isHuman: boolean; hasWallet: boolean } }
expect(body.exists).toBe(true)
expect(body.bot.id).toBe(botId)
expect(body.bot.name).toBe(name)
// Same key set as POST /login's 200 body
expect(body.bot.isHuman).toBe(false)
expect(body.bot.hasWallet).toBe(false)
})
it('performs no writes: querying /me for an unregistered creator pubkey does not create a row', async () => {
// A non-creator pubkey with a valid token and no bot row must stay exists:false
// with zero side effects (GET /me never inserts/updates).
const pk = getPublicKey(generateSecretKey())
const token = createJwt(pk)
const before = await db.select({ id: schema.bots.id }).from(schema.bots)
await app.request('/api/auth/me', { headers: { Authorization: `Bearer ${token}` } })
const after = await db.select({ id: schema.bots.id }).from(schema.bots)
expect(after.length).toBe(before.length)
})
})