mirror of
https://github.com/saltbo/zpan.git
synced 2026-09-11 05:22:46 +08:00
111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi'
|
|
import { requireAdmin } from '../../middleware/auth'
|
|
import type { Env } from '../../middleware/platform'
|
|
import { deleteAuthProvider, listAuthProviders, upsertAuthProvider } from '../../usecases/site/auth-provider'
|
|
import { errorResponse, jsonBody, jsonContent } from '../openapi'
|
|
|
|
// Full management shape. Public consumers receive the minimal provider projection
|
|
// from configz instead.
|
|
const authProviderSchema = z
|
|
.object({
|
|
providerId: z.string(),
|
|
type: z.string(),
|
|
enabled: z.boolean(),
|
|
name: z.string(),
|
|
icon: z.string(),
|
|
clientId: z.string(),
|
|
discoveryUrl: z.string().nullable(),
|
|
scopes: z.array(z.string()).nullable(),
|
|
callbackUri: z.string(),
|
|
clientSecret: z.string(),
|
|
})
|
|
.openapi('AuthProvider')
|
|
|
|
const authProviderListSchema = z
|
|
.object({
|
|
items: z.array(authProviderSchema),
|
|
total: z.number().int(),
|
|
page: z.number().int(),
|
|
pageSize: z.number().int(),
|
|
callbackBaseUri: z.string(),
|
|
})
|
|
.openapi('AuthProviderList')
|
|
|
|
const upsertSchema = z.object({
|
|
type: z.enum(['builtin', 'oidc']),
|
|
clientId: z.string().min(1),
|
|
clientSecret: z.string().min(1),
|
|
enabled: z.boolean(),
|
|
discoveryUrl: z.string().url().optional(),
|
|
scopes: z.array(z.string()).optional(),
|
|
})
|
|
|
|
const listRoute = createRoute({
|
|
operationId: 'listAuthProviders',
|
|
summary: 'List auth providers',
|
|
tags: ['Auth Providers'],
|
|
method: 'get',
|
|
path: '/',
|
|
middleware: [requireAdmin] as const,
|
|
responses: { 200: jsonContent(authProviderListSchema, 'Auth providers') },
|
|
})
|
|
|
|
const upsertRoute = createRoute({
|
|
operationId: 'upsertAuthProvider',
|
|
summary: 'Create or update an auth provider',
|
|
tags: ['Auth Providers'],
|
|
method: 'put',
|
|
path: '/{providerId}',
|
|
middleware: [requireAdmin] as const,
|
|
request: { params: z.object({ providerId: z.string() }), ...jsonBody(upsertSchema) },
|
|
responses: {
|
|
200: jsonContent(authProviderSchema, 'Upserted auth provider'),
|
|
400: errorResponse('Invalid provider'),
|
|
402: errorResponse('Feature not available'),
|
|
},
|
|
})
|
|
|
|
const deleteProviderRoute = createRoute({
|
|
operationId: 'deleteAuthProvider',
|
|
summary: 'Delete an auth provider',
|
|
tags: ['Auth Providers'],
|
|
method: 'delete',
|
|
path: '/{providerId}',
|
|
middleware: [requireAdmin] as const,
|
|
request: { params: z.object({ providerId: z.string() }) },
|
|
responses: {
|
|
204: { description: 'Deleted auth provider' },
|
|
400: errorResponse('Invalid provider'),
|
|
},
|
|
})
|
|
|
|
function resolveAuthBaseUri(c: { get(key: 'platform'): Env['Variables']['platform']; req: { url: string } }): string {
|
|
// Prefer the configured Better Auth base URL because OAuth providers validate
|
|
// redirects against the auth runtime base. Fall back to request origin for
|
|
// deployments that rely on per-request Worker/Node origin behavior.
|
|
return c.get('platform').getEnv('BETTER_AUTH_URL')?.trim() || new URL(c.req.url).origin
|
|
}
|
|
|
|
// Auth-provider management resource. Public enabled providers are projected by
|
|
// /api/configz; every route here is admin-only.
|
|
export const authProviders = new OpenAPIHono<Env>()
|
|
.openapi(listRoute, async (c) => {
|
|
const authOrigin = resolveAuthBaseUri(c)
|
|
const { items } = await listAuthProviders(c.get('deps'), { authOrigin })
|
|
return c.json({ items, total: items.length, page: 1, pageSize: items.length, callbackBaseUri: authOrigin }, 200)
|
|
})
|
|
.openapi(upsertRoute, async (c) => {
|
|
const authOrigin = resolveAuthBaseUri(c)
|
|
const result = await upsertAuthProvider(c.get('deps'), c.req.valid('param').providerId, c.req.valid('json'), {
|
|
authOrigin,
|
|
})
|
|
if (!result.ok) throw result.error
|
|
return c.json(result.config, 200)
|
|
})
|
|
.openapi(deleteProviderRoute, async (c) => {
|
|
const providerId = c.req.valid('param').providerId
|
|
const result = await deleteAuthProvider(c.get('deps'), providerId)
|
|
if (!result.ok) throw result.error
|
|
return c.body(null, 204)
|
|
})
|