1
1
mirror of https://github.com/ZeroCatDev/ClassworksKV.git synced 2025-12-07 13:03:09 +00:00

feat: 添加设备信息提取功能,增强 UUID 认证中间件的错误处理

This commit is contained in:
Sunwuyuan 2025-11-16 14:46:05 +08:00
parent 4ff64ad514
commit 4ae023afb0
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
2 changed files with 34 additions and 212 deletions

View File

@ -93,7 +93,22 @@ export const uuidAuth = async (req, res, next) => {
next(error);
}
};
export const extractDeviceInfo = async (req,res,next) => {
var uuid= extractUuid(req);
if (!uuid) {
throw errors.createError(400, "需要提供设备UUID");
}
const device = await prisma.device.findUnique({
where: { uuid },
});
if (!device) {
throw errors.createError(404, "设备不存在");
}
res.locals.device = device;
res.locals.deviceId = device.id;
next();
}
/**
* 从请求中提取UUID
*/

View File

@ -1,6 +1,6 @@
import { Router } from "express";
const router = Router();
import { uuidAuth } from "../middleware/uuidAuth.js";
import { uuidAuth, extractDeviceInfo } from "../middleware/uuidAuth.js";
import { PrismaClient } from "@prisma/client";
import crypto from "crypto";
import errors from "../utils/errors.js";
@ -131,21 +131,21 @@ router.get(
}
return res.json({
id: device.id,
uuid: device.uuid,
name: device.name,
hasPassword: !!device.password,
passwordHint: device.passwordHint,
createdAt: device.createdAt,
account: device.account ? {
id: device.account.id,
name: device.account.name,
email: device.account.email,
avatarUrl: device.account.avatarUrl,
} : null,
isBoundToAccount: !!device.account,
namespace: device.namespace,
});
id: device.id,
uuid: device.uuid,
name: device.name,
hasPassword: !!device.password,
passwordHint: device.passwordHint,
createdAt: device.createdAt,
account: device.account ? {
id: device.account.id,
name: device.account.name,
email: device.account.email,
avatarUrl: device.account.avatarUrl,
} : null,
isBoundToAccount: !!device.account,
namespace: device.namespace,
});
})
);/**
* PUT /devices/:uuid/name
@ -153,7 +153,7 @@ router.get(
*/
router.put(
"/:uuid/name",
uuidAuth,
extractDeviceInfo,
errors.catchAsync(async (req, res, next) => {
const { name } = req.body;
const device = res.locals.device;
@ -180,202 +180,7 @@ router.put(
})
);
/**
* POST /devices/:uuid/password
* 初次设置设备密码 (无需认证仅当设备未设置密码时)
*/
router.post(
"/:uuid/password",
errors.catchAsync(async (req, res, next) => {
const { uuid } = req.params;
const newPassword = req.query.newPassword || req.body.newPassword;
if (!newPassword) {
return next(errors.createError(400, "新密码是必需的"));
}
// 查找设备
const device = await prisma.device.findUnique({
where: { uuid },
});
if (!device) {
return next(errors.createError(404, "设备不存在"));
}
// 只有在设备未设置密码时才允许无认证设置
if (device.password) {
return next(errors.createError(403, "设备已设置密码,请使用修改密码接口"));
}
const hashedPassword = await hashPassword(newPassword);
await prisma.device.update({
where: { id: device.id },
data: {
password: hashedPassword,
},
});
return res.json({
success: true,
message: "密码设置成功",
});
})
);
/**
* PUT /devices/:uuid/password
* 修改设备密码 (需要UUID认证和当前密码验证账户拥有者除外)
*/
router.put(
"/:uuid/password",
uuidAuth,
errors.catchAsync(async (req, res, next) => {
const currentPassword = req.query.currentPassword;
const newPassword = req.query.newPassword || req.body.newPassword;
const passwordHint = req.query.passwordHint || req.body.passwordHint;
const device = res.locals.device;
const isAccountOwner = res.locals.isAccountOwner;
if (!newPassword) {
return next(errors.createError(400, "新密码是必需的"));
}
// 如果是账户拥有者,无需验证当前密码
if (!isAccountOwner) {
if (!device.password) {
return next(errors.createError(400, "设备未设置密码,请使用设置密码接口"));
}
if (!currentPassword) {
return next(errors.createError(400, "当前密码是必需的"));
}
// 验证当前密码
const isCurrentPasswordValid = await verifyDevicePassword(currentPassword, device.password);
if (!isCurrentPasswordValid) {
return next(errors.createError(401, "当前密码错误"));
}
}
const hashedNewPassword = await hashPassword(newPassword);
await prisma.device.update({
where: { id: device.id },
data: {
password: hashedNewPassword,
passwordHint: passwordHint !== undefined ? passwordHint : device.passwordHint,
},
});
return res.json({
success: true,
message: "密码修改成功",
});
})
);
/**
* PUT /devices/:uuid/password-hint
* 设置密码提示 (需要UUID认证)
*/
router.put(
"/:uuid/password-hint",
uuidAuth,
errors.catchAsync(async (req, res, next) => {
const { passwordHint } = req.body;
const device = res.locals.device;
await prisma.device.update({
where: { id: device.id },
data: { passwordHint: passwordHint || null },
});
return res.json({
success: true,
message: "密码提示设置成功",
passwordHint: passwordHint || null,
});
})
);
/**
* GET /devices/:uuid/password-hint
* 获取设备密码提示 (无需认证)
*/
router.get(
"/:uuid/password-hint",
errors.catchAsync(async (req, res, next) => {
const { uuid } = req.params;
const device = await prisma.device.findUnique({
where: { uuid },
select: {
passwordHint: true,
},
});
if (!device) {
return next(errors.createError(404, "设备不存在"));
}
return res.json({
success: true,
passwordHint: device.passwordHint || null,
});
})
);
/**
* DELETE /devices/:uuid/password
* 删除设备密码 (需要UUID认证和密码验证账户拥有者除外)
*/
router.delete(
"/:uuid/password",
uuidAuth,
errors.catchAsync(async (req, res, next) => {
const password = req.query.password;
const device = res.locals.device;
const isAccountOwner = res.locals.isAccountOwner;
if (!device.password) {
return next(errors.createError(400, "设备未设置密码"));
}
// 如果不是账户拥有者,需要验证密码
if (!isAccountOwner) {
if (!password) {
return next(errors.createError(400, "密码是必需的"));
}
// 验证密码
const isPasswordValid = await verifyDevicePassword(password, device.password);
if (!isPasswordValid) {
return next(errors.createError(401, "密码错误"));
}
}
try {
await prisma.device.update({
where: { id: device.id },
data: {
password: null,
passwordHint: null,
},
});
return res.json({
success: true,
message: "密码删除成功",
});
} catch (error) {
throw error;
}
})
);
export default router;
/**
* GET /devices/online
@ -408,3 +213,5 @@ router.get(
res.json({ success: true, devices });
})
);
export default router;