1
1
mirror of https://github.com/ZeroCatDev/ClassworksKV.git synced 2025-10-22 02:03:11 +00:00
2025-10-03 21:22:18 +08:00

126 lines
3.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 设备管理中间件
*
* 提供统一的设备UUID处理逻辑
* 1. deviceMiddleware - 自动获取或创建设备将设备信息存储到res.locals.device
* 2. deviceInfoMiddleware - 仅获取设备信息,不创建新设备
* 3. passwordMiddleware - 验证设备密码
*/
import { PrismaClient } from "@prisma/client";
import errors from "../utils/errors.js";
import { verifyDevicePassword } from "../utils/crypto.js";
const prisma = new PrismaClient();
/**
* 设备中间件 - 统一处理设备UUID
*
* 从req.params.deviceUuid、req.params.namespace或req.body.deviceUuid获取UUID
* 如果设备不存在则自动创建
* 将设备信息存储到res.locals.device
*
* 使用方式:
* router.post('/path', deviceMiddleware, handler)
* router.get('/path/:deviceUuid', deviceMiddleware, handler)
*/
export const deviceMiddleware = errors.catchAsync(async (req, res, next) => {
const deviceUuid = req.params.deviceUuid || req.params.namespace || req.body.deviceUuid;
if (!deviceUuid) {
return next(errors.createError(400, "缺少设备UUID"));
}
// 查找或创建设备
let device = await prisma.device.findUnique({
where: { uuid: deviceUuid },
});
if (!device) {
// 设备不存在,自动创建
device = await prisma.device.create({
data: {
uuid: deviceUuid,
name: null,
password: null,
passwordHint: null,
accountId: null,
},
});
}
// 将设备信息存储到res.locals
res.locals.device = device;
next();
});
/**
* 设备信息中间件 - 仅获取设备信息,不创建新设备
*
* 从req.params.deviceUuid获取UUID
* 如果设备不存在则返回404错误
* 将设备信息存储到res.locals.device
*
* 使用方式:
* router.get('/path/:deviceUuid', deviceInfoMiddleware, handler)
*/
export const deviceInfoMiddleware = errors.catchAsync(async (req, res, next) => {
const deviceUuid = req.params.deviceUuid || req.params.namespace;
if (!deviceUuid) {
return next(errors.createError(400, "缺少设备UUID"));
}
// 查找设备
const device = await prisma.device.findUnique({
where: { uuid: deviceUuid },
});
if (!device) {
return next(errors.createError(404, "设备不存在"));
}
// 将设备信息存储到res.locals
res.locals.device = device;
next();
});
/**
* 密码验证中间件 - 验证设备密码
*
* 前置条件必须先使用deviceMiddleware或deviceInfoMiddleware
* 从req.body.password获取密码
* 如果设备有密码但未提供或密码错误则返回401错误
*
* 特殊规则如果设备绑定了账户且req.account存在且匹配则跳过密码验证
*
* 使用方式:
* router.post('/path', deviceMiddleware, passwordMiddleware, handler)
*/
export const passwordMiddleware = errors.catchAsync(async (req, res, next) => {
const device = res.locals.device;
const { password } = req.body;
if (!device) {
return next(errors.createError(500, "设备信息未加载请先使用deviceMiddleware"));
}
// 如果设备绑定了账户,且请求中有账户信息且匹配,则跳过密码验证
if (device.accountId && req.account && req.account.id === device.accountId) {
return next();
}
// 如果设备有密码,验证密码
if (device.password) {
if (!password) {
return next(errors.createError(401, "设备需要密码"));
}
const isValid = await verifyDevicePassword(password, device.password);
if (!isValid) {
return next(errors.createError(401, "密码错误"));
}
}
next();
});