scriptflow/server/auth.ts
Song367 b49d703e3c
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m22s
一键转换模式优化
2026-03-11 21:53:41 +08:00

86 lines
2.5 KiB
TypeScript

import crypto from 'node:crypto';
import type { NextFunction, Request, Response } from 'express';
import { createSession, createUser, deleteSession, findUserBySessionToken, findUserByUsername } from './db.ts';
import type { AuthenticatedUser } from './types.ts';
declare global {
namespace Express {
interface Request {
authUser?: AuthenticatedUser;
authToken?: string;
}
}
}
export function hashPassword(password: string, salt = crypto.randomBytes(16).toString('hex')) {
const hash = crypto.scryptSync(password, salt, 64).toString('hex');
return { hash, salt };
}
export function verifyPassword(password: string, passwordHash: string, passwordSalt: string) {
const { hash } = hashPassword(password, passwordSalt);
return crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(passwordHash, 'hex'));
}
export function issueSession(userId: number) {
const token = crypto.randomBytes(32).toString('hex');
createSession(token, userId);
return token;
}
export function registerUser(username: string, password: string) {
if (findUserByUsername(username)) {
throw new Error('账号已存在');
}
const { hash, salt } = hashPassword(password);
const user = createUser(username, hash, salt);
if (!user) {
throw new Error('账号创建失败');
}
const token = issueSession(user.id);
return {
token,
user: { id: user.id, username: user.username },
};
}
export function loginUser(username: string, password: string) {
const user = findUserByUsername(username);
if (!user || !verifyPassword(password, user.password_hash, user.password_salt)) {
throw new Error('账号或密码错误');
}
const token = issueSession(user.id);
return {
token,
user: { id: user.id, username: user.username },
};
}
export function requireAuth(req: Request, res: Response, next: NextFunction) {
const header = req.headers.authorization || '';
const token = header.startsWith('Bearer ') ? header.slice(7) : '';
if (!token) {
res.status(401).json({ error: '未登录' });
return;
}
const user = findUserBySessionToken(token);
if (!user) {
res.status(401).json({ error: '登录已失效' });
return;
}
req.authToken = token;
req.authUser = { id: user.id, username: user.username };
next();
}
export function resolveSession(token: string) {
const user = findUserBySessionToken(token);
return user ? { id: user.id, username: user.username } : null;
}
export function logoutSession(token: string) {
deleteSession(token);
}