1
1
mirror of https://github.com/ZeroCatDev/ClassworksKV.git synced 2025-12-08 22:53:10 +00:00
ClassworksKV/routes/device.js
copilot-swe-agent[bot] 6b3e58d68f Deprecate device password management endpoints to resolve JWT token error
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
2025-11-14 14:15:04 +00:00

266 lines
7.0 KiB
JavaScript
Raw 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.

import { Router } from "express";
const router = Router();
import { uuidAuth } from "../middleware/uuidAuth.js";
import { PrismaClient } from "@prisma/client";
import crypto from "crypto";
import errors from "../utils/errors.js";
import { hashPassword, verifyDevicePassword } from "../utils/crypto.js";
import { getOnlineDevices } from "../utils/socket.js";
const prisma = new PrismaClient();
/**
* 为新设备创建默认的自动登录配置
* @param {number} deviceId - 设备ID
*/
async function createDefaultAutoAuth(deviceId) {
try {
// 创建默认的自动授权配置不需要密码、类型是classroom一体机
await prisma.autoAuth.create({
data: {
deviceId: deviceId,
password: null, // 无密码
deviceType: "classroom", // 一体机类型
isReadOnly: false, // 非只读
},
});
} catch (error) {
console.error('创建默认自动登录配置失败:', error);
// 这里不抛出错误,避免影响设备创建流程
}
}
/**
* POST /devices
* 注册新设备
*/
router.post(
"/",
errors.catchAsync(async (req, res, next) => {
const { uuid, deviceName, namespace } = req.body;
if (!uuid) {
return next(errors.createError(400, "设备UUID是必需的"));
}
if (!deviceName) {
return next(errors.createError(400, "设备名称是必需的"));
}
// 检查UUID是否已存在
const existingDevice = await prisma.device.findUnique({
where: { uuid },
});
if (existingDevice) {
return next(errors.createError(409, "设备UUID已存在"));
}
// 处理 namespace如果没有提供则使用 uuid
const deviceNamespace = namespace && namespace.trim() ? namespace.trim() : uuid;
// 检查 namespace 是否已被使用
const existingNamespace = await prisma.device.findUnique({
where: { namespace: deviceNamespace },
});
if (existingNamespace) {
return next(errors.createError(409, "该 namespace 已被使用"));
}
// 创建设备
const device = await prisma.device.create({
data: {
uuid,
name: deviceName,
namespace: deviceNamespace,
},
});
// 为新设备创建默认的自动登录配置
await createDefaultAutoAuth(device.id);
return res.status(201).json({
success: true,
device: {
id: device.id,
uuid: device.uuid,
name: device.name,
namespace: device.namespace,
createdAt: device.createdAt,
},
});
})
);
/**
* GET /devices/:uuid
* 获取设备信息 (公开接口,无需认证)
*/
router.get(
"/:uuid",
errors.catchAsync(async (req, res, next) => {
const { uuid } = req.params;
// 查找设备,包含绑定的账户信息
const device = await prisma.device.findUnique({
where: { uuid },
include: {
account: {
select: {
id: true,
name: true,
email: true,
avatarUrl: true,
},
},
},
});
if (!device) {
return next(errors.createError(404, "设备不存在"));
}
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,
});
})
);/**
* PUT /devices/:uuid/name
* 设置设备名称 (需要UUID认证)
*/
router.put(
"/:uuid/name",
uuidAuth,
errors.catchAsync(async (req, res, next) => {
const { name } = req.body;
const device = res.locals.device;
if (!name) {
return next(errors.createError(400, "设备名称是必需的"));
}
const updatedDevice = await prisma.device.update({
where: { id: device.id },
data: { name },
});
return res.json({
success: true,
device: {
id: updatedDevice.id,
uuid: updatedDevice.uuid,
name: updatedDevice.name,
hasPassword: !!updatedDevice.password,
passwordHint: updatedDevice.passwordHint,
},
});
})
);
/**
* POST /devices/:uuid/password
* @deprecated 此端点已弃用,请使用 AutoAuth 自动授权功能
* 初次设置设备密码 (无需认证,仅当设备未设置密码时)
*/
router.post(
"/:uuid/password",
errors.catchAsync(async (req, res, next) => {
return next(errors.createError(410, "此功能已弃用,请使用 AutoAuth 自动授权功能代替设备密码"));
})
);
/**
* PUT /devices/:uuid/password
* @deprecated 此端点已弃用,请使用 AutoAuth 自动授权功能
* 修改设备密码 (需要UUID认证和当前密码验证账户拥有者除外)
*/
router.put(
"/:uuid/password",
errors.catchAsync(async (req, res, next) => {
return next(errors.createError(410, "此功能已弃用,请使用 AutoAuth 自动授权功能代替设备密码"));
})
);
/**
* PUT /devices/:uuid/password-hint
* @deprecated 此端点已弃用,请使用 AutoAuth 自动授权功能
* 设置密码提示 (需要UUID认证)
*/
router.put(
"/:uuid/password-hint",
errors.catchAsync(async (req, res, next) => {
return next(errors.createError(410, "此功能已弃用,请使用 AutoAuth 自动授权功能代替设备密码"));
})
);
/**
* GET /devices/:uuid/password-hint
* @deprecated 此端点已弃用,请使用 AutoAuth 自动授权功能
* 获取设备密码提示 (无需认证)
*/
router.get(
"/:uuid/password-hint",
errors.catchAsync(async (req, res, next) => {
return next(errors.createError(410, "此功能已弃用,请使用 AutoAuth 自动授权功能代替设备密码"));
})
);
/**
* DELETE /devices/:uuid/password
* @deprecated 此端点已弃用,请使用 AutoAuth 自动授权功能
* 删除设备密码 (需要UUID认证和密码验证账户拥有者除外)
*/
router.delete(
"/:uuid/password",
errors.catchAsync(async (req, res, next) => {
return next(errors.createError(410, "此功能已弃用,请使用 AutoAuth 自动授权功能代替设备密码"));
})
);
export default router;
/**
* GET /devices/online
* 查询在线设备WebSocket 已连接)
* 返回:[{ uuid, connections, name? }]
*/
router.get(
"/online",
errors.catchAsync(async (req, res) => {
const list = getOnlineDevices();
if (list.length === 0) {
return res.json({ success: true, devices: [] });
}
// 补充设备名称
const uuids = list.map((x) => x.uuid);
const rows = await prisma.device.findMany({
where: { uuid: { in: uuids } },
select: { uuid: true, name: true },
});
const nameMap = new Map(rows.map((r) => [r.uuid, r.name]));
const devices = list.map((x) => ({
uuid: x.uuid,
connections: x.connections,
name: nameMap.get(x.uuid) || null,
}));
res.json({ success: true, devices });
})
);