[cards] Authenticate channel routes and return channel lists (#121)

This commit is contained in:
dukedotdev
2026-10-13 00:52:03 -04:00
committed by GitHub
parent 6f9348222a
commit 1f4c3e5fc0
4 changed files with 53 additions and 2 deletions
+1
View File
@@ -16,6 +16,7 @@
},
"dependencies": {
"@repo/hono-helpers": "workspace:*",
"@repo/jwt": "workspace:*",
"hono": "4.13.5",
"workers-tagged-logger": "1.0.1"
},
+11
View File
@@ -2,6 +2,7 @@ import { Hono } from 'hono'
import { useWorkersLogger } from 'workers-tagged-logger'
import { withNotFound, withOnError } from '@repo/hono-helpers'
import { validateAndGetAccountId } from '@repo/jwt'
import type { App } from './context'
@@ -22,5 +23,15 @@ const app = new Hono<App>()
.get('/', async (c) => {
return c.text('hello, world!')
})
.get('/iam/me/channels/:channel', async (c) => {
const accountId = await validateAndGetAccountId(c.req.raw, await c.env.JWT_SECRET.get())
if (accountId === null) return c.body(null, 401)
const channel = c.req.param('channel')
if (!['None', 'Announcements', 'JustInTimeTutorials'].includes(channel)) {
return c.body(null, 400)
}
// GetChannelMessages decodes a bare List<InAppMessageDTO>. No campaigns are configured.
return c.json([])
})
export default app
+38 -2
View File
@@ -1,8 +1,44 @@
import { SELF } from 'cloudflare:test'
import { expect, it } from 'vitest'
import { adminSecretsStore, env, SELF } from 'cloudflare:test'
import { sign } from 'hono/jwt'
import { beforeAll, expect, it } from 'vitest'
import type { Env } from '../../context'
declare module 'cloudflare:test' {
interface ProvidedEnv extends Env {}
}
beforeAll(async () => {
await adminSecretsStore(env.JWT_SECRET).create('cards-test-secret')
})
async function bearer() {
const token = await sign(
{ sub: '205', exp: Math.floor(Date.now() / 1000) + 60 },
'cards-test-secret',
'HS256'
)
return { Authorization: `Bearer ${token}` }
}
it('response with hello world', async () => {
const res = await SELF.fetch('https://example.com')
expect(res.status).toBe(200)
expect(await res.text()).toMatchInlineSnapshot(`"hello, world!"`)
})
it('in-app message channels return a bare list and require authentication', async () => {
const url = 'https://example.com/iam/me/channels/Announcements'
expect((await SELF.fetch(url)).status).toBe(401)
for (const channel of ['Announcements', 'JustInTimeTutorials', 'None']) {
const response = await SELF.fetch(`https://example.com/iam/me/channels/${channel}`, {
headers: await bearer(),
})
expect(response.status).toBe(200)
expect(await response.json()).toEqual([])
}
expect(
(await SELF.fetch('https://example.com/iam/me/channels/Unknown', { headers: await bearer() }))
.status
).toBe(400)
})