pl / src /api /auth.ts
ghuser1's picture
Upload 2 files
3c49634 verified
Raw
History Blame Contribute Delete
2.23 kB
import { Hono } from 'hono';
import type { Context, MiddlewareHandler } from 'hono';
import { eq } from 'drizzle-orm';
import { settings } from '../db/schema';
import { getFullSettings } from './settings';
import { hashPassword, isPasswordHash, verifyPassword } from '../password';
import type { Env, Variables } from '../index';
export const authApi = new Hono<{ Bindings: Env; Variables: Variables }>();
type AppContext = Context<{ Bindings: Env; Variables: Variables }>;
async function verifyAndUpgradePassword(c: AppContext, provided: string): Promise<{ required: boolean; authorized: boolean }> {
const s = await getFullSettings(c.var.db);
if (!s.accessPassword) return { required: false, authorized: true };
const authorized = verifyPassword(provided, s.accessPassword);
if (authorized && provided && !isPasswordHash(s.accessPassword)) {
await c.var.db
.update(settings)
.set({ accessPassword: hashPassword(provided), updatedAt: Date.now() })
.where(eq(settings.id, 'default'));
}
return { required: true, authorized };
}
// 检查是否需要密码 + 当前请求是否已通过验证
authApi.get('/check', async (c) => {
const provided = c.req.header('X-Access-Password') || '';
return c.json(await verifyAndUpgradePassword(c, provided));
});
// 验证密码(用于显式登陆)
authApi.post('/login', async (c) => {
const body = await c.req.json<{ password?: string }>().catch(() => ({} as { password?: string }));
const result = await verifyAndUpgradePassword(c, body.password || '');
if (!result.required) return c.json({ ok: true });
if (!result.authorized) {
return c.json({ error: 'invalid_password' }, 401);
}
return c.json({ ok: true });
});
export const authMiddleware: MiddlewareHandler<{ Bindings: Env; Variables: Variables }> = async (c, next) => {
// 放行 /api/auth/* —— 内部检查/登陆都不需要密码
if (c.req.path.startsWith('/api/auth')) return next();
const provided = c.req.header('X-Access-Password') || '';
const result = await verifyAndUpgradePassword(c, provided);
if (!result.required) return next();
if (!result.authorized) {
return c.json({ error: 'unauthorized' }, 401);
}
return next();
};