File size: 2,225 Bytes
cfea436
3c49634
 
 
cfea436
3c49634
cfea436
 
 
 
3c49634
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cfea436
 
 
3c49634
cfea436
 
 
 
 
3c49634
 
 
cfea436
 
 
 
 
 
 
 
 
3c49634
 
 
cfea436
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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();
};