mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
90 lines
3.1 KiB
TypeScript
90 lines
3.1 KiB
TypeScript
import { Hono } from 'hono'
|
|
import { SignJWT } from 'jose'
|
|
import { z } from 'zod'
|
|
import { configuration } from '../../configuration'
|
|
import { constantTimeEquals } from '../../utils/crypto'
|
|
import { parseAccessToken } from '../../utils/accessToken'
|
|
import { validateTelegramInitData } from '../telegramInitData'
|
|
import { getOrCreateOwnerId } from '../ownerId'
|
|
import type { WebAppEnv } from '../middleware/auth'
|
|
import type { Store } from '../../store'
|
|
|
|
const telegramAuthSchema = z.object({
|
|
initData: z.string()
|
|
})
|
|
|
|
const accessTokenAuthSchema = z.object({
|
|
accessToken: z.string()
|
|
})
|
|
|
|
const authBodySchema = z.union([telegramAuthSchema, accessTokenAuthSchema])
|
|
|
|
export function createAuthRoutes(jwtSecret: Uint8Array, store: Store): Hono<WebAppEnv> {
|
|
const app = new Hono<WebAppEnv>()
|
|
|
|
app.post('/auth', async (c) => {
|
|
const json = await c.req.json().catch(() => null)
|
|
const parsed = authBodySchema.safeParse(json)
|
|
if (!parsed.success) {
|
|
return c.json({ error: 'Invalid body' }, 400)
|
|
}
|
|
|
|
let userId: number
|
|
let username: string | undefined
|
|
let firstName: string | undefined
|
|
let lastName: string | undefined
|
|
let namespace: string
|
|
|
|
// Access Token authentication (CLI_API_TOKEN)
|
|
if ('accessToken' in parsed.data) {
|
|
const parsedToken = parseAccessToken(parsed.data.accessToken)
|
|
if (!parsedToken || !constantTimeEquals(parsedToken.baseToken, configuration.cliApiToken)) {
|
|
return c.json({ error: 'Invalid access token' }, 401)
|
|
}
|
|
userId = await getOrCreateOwnerId()
|
|
firstName = 'Web User'
|
|
namespace = parsedToken.namespace
|
|
} else {
|
|
if (!configuration.telegramEnabled || !configuration.telegramBotToken) {
|
|
return c.json({ error: 'Telegram authentication is disabled. Configure TELEGRAM_BOT_TOKEN.' }, 503)
|
|
}
|
|
|
|
// Telegram initData authentication
|
|
const result = validateTelegramInitData(parsed.data.initData, configuration.telegramBotToken)
|
|
if (!result.ok) {
|
|
return c.json({ error: result.error }, 401)
|
|
}
|
|
|
|
const telegramUserId = String(result.user.id)
|
|
const storedUser = store.getUser('telegram', telegramUserId)
|
|
if (!storedUser) {
|
|
return c.json({ error: 'not_bound' }, 401)
|
|
}
|
|
|
|
userId = await getOrCreateOwnerId()
|
|
username = result.user.username
|
|
firstName = result.user.first_name
|
|
lastName = result.user.last_name
|
|
namespace = storedUser.namespace
|
|
}
|
|
|
|
const token = await new SignJWT({ uid: userId, ns: namespace })
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('15m')
|
|
.sign(jwtSecret)
|
|
|
|
return c.json({
|
|
token,
|
|
user: {
|
|
id: userId,
|
|
username,
|
|
firstName,
|
|
lastName
|
|
}
|
|
})
|
|
})
|
|
|
|
return app
|
|
}
|