diff --git a/middleware/device.js b/middleware/device.js index 96e720d..0c8b0a0 100644 --- a/middleware/device.js +++ b/middleware/device.js @@ -14,17 +14,17 @@ import {analyzeDevice} from "../utils/deviceDetector.js"; /** * 为新设备创建默认的自动登录配置 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID */ -async function createDefaultAutoAuth(deviceId) { +async function createDefaultAutoAuth(deviceid) { try { // 创建默认的自动授权配置:不需要密码、类型是classroom(一体机) await prisma.autoAuth.create({ data: { - deviceId: deviceId, + deviceid: deviceid, password: null, // 无密码 - deviceType: "classroom", // 一体机类型 - isReadOnly: false, // 非只读 + devicetype: "classroom", // 一体机类型 + isreadonly: false, // 非只读 }, }); } catch (error) { @@ -59,7 +59,7 @@ export const deviceMiddleware = errors.catchAsync(async (req, res, next) => { if (!device) { // 设备不存在,自动创建并生成智能设备名称 const userAgent = req.headers['user-agent']; - const customDeviceType = req.body.deviceType || req.query.deviceType; + const customDeviceType = req.body.devicetype || req.query.devicetype; const note = req.body.note || req.query.note; // 生成设备名称,确保不为空 @@ -70,7 +70,7 @@ export const deviceMiddleware = errors.catchAsync(async (req, res, next) => { uuid: deviceUuid, name: deviceName, password: null, - passwordHint: null, + passwordhint: null, accountId: null, }, }); diff --git a/middleware/kvTokenAuth.js b/middleware/kvTokenAuth.js index 927022f..448d080 100644 --- a/middleware/kvTokenAuth.js +++ b/middleware/kvTokenAuth.js @@ -22,7 +22,7 @@ export const kvTokenAuth = async (req, res, next) => { } // 查找token对应的应用安装信息 - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: {token}, include: { device: true, @@ -36,7 +36,7 @@ export const kvTokenAuth = async (req, res, next) => { // 将信息存储到res.locals供后续使用 res.locals.device = appInstall.device; res.locals.appInstall = appInstall; - res.locals.deviceId = appInstall.device.id; + res.locals.deviceid = appInstall.device.id; res.locals.token = token; next(); } catch (error) { diff --git a/middleware/uuidAuth.js b/middleware/uuidAuth.js index b332dff..d34a712 100644 --- a/middleware/uuidAuth.js +++ b/middleware/uuidAuth.js @@ -33,7 +33,7 @@ export const uuidAuth = async (req, res, next) => { // 存储设备信息到locals res.locals.device = device; - res.locals.deviceId = device.id; + res.locals.deviceid = device.id; // 3. 验证密码或JWT(二选一) const password = extractPassword(req); @@ -104,7 +104,7 @@ export const extractDeviceInfo = async (req, res, next) => { throw errors.createError(404, "设备不存在"); } res.locals.device = device; - res.locals.deviceId = device.id; + res.locals.deviceid = device.id; next(); } diff --git a/prisma/migrations/20260201105825_fix_timestamp_defaults/migration.sql b/prisma/migrations/20260201105825_fix_timestamp_defaults/migration.sql new file mode 100644 index 0000000..5058103 --- /dev/null +++ b/prisma/migrations/20260201105825_fix_timestamp_defaults/migration.sql @@ -0,0 +1,19 @@ +-- AlterTable +ALTER TABLE "account" ALTER COLUMN "createdat" SET DEFAULT timezone('Asia/Shanghai', now()), +ALTER COLUMN "updatedat" SET DEFAULT timezone('Asia/Shanghai', now()); + +-- AlterTable +ALTER TABLE "appinstall" ALTER COLUMN "installedat" SET DEFAULT timezone('Asia/Shanghai', now()), +ALTER COLUMN "updatedat" SET DEFAULT timezone('Asia/Shanghai', now()); + +-- AlterTable +ALTER TABLE "autoauth" ALTER COLUMN "createdat" SET DEFAULT timezone('Asia/Shanghai', now()), +ALTER COLUMN "updatedat" SET DEFAULT timezone('Asia/Shanghai', now()); + +-- AlterTable +ALTER TABLE "device" ALTER COLUMN "createdat" SET DEFAULT timezone('Asia/Shanghai', now()), +ALTER COLUMN "updatedat" SET DEFAULT timezone('Asia/Shanghai', now()); + +-- AlterTable +ALTER TABLE "kvstore" ALTER COLUMN "createdat" SET DEFAULT timezone('Asia/Shanghai', now()), +ALTER COLUMN "updatedat" SET DEFAULT timezone('Asia/Shanghai', now()); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e949251..446dd97 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,8 +16,8 @@ model account { avatarurl String? @db.VarChar(191) providerdata Json? @db.Json accesstoken String? - createdat DateTime @default(now()) @db.Timestamptz(6) - updatedat DateTime @db.Timestamptz(6) + createdat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @db.Timestamptz(6) + updatedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @updatedAt @db.Timestamptz(6) refreshtoken String? refreshtokenexpiry DateTime? @db.Timestamptz(6) tokenversion Int @default(1) @@ -32,8 +32,8 @@ model appinstall { appid String @db.VarChar(191) token String @unique(map: "idx_18055_appinstall_token_key") @db.VarChar(191) note String? @db.VarChar(191) - installedat DateTime @default(now()) @db.Timestamptz(6) - updatedat DateTime @db.Timestamptz(6) + installedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @db.Timestamptz(6) + updatedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @updatedAt @db.Timestamptz(6) devicetype String? @db.VarChar(191) isreadonly Boolean @default(false) device device @relation(fields: [deviceid], references: [id], onDelete: Cascade) @@ -47,8 +47,8 @@ model autoauth { password String? @db.VarChar(191) devicetype String? @db.VarChar(191) isreadonly Boolean @default(false) - createdat DateTime @default(now()) @db.Timestamptz(6) - updatedat DateTime @db.Timestamptz(6) + createdat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @db.Timestamptz(6) + updatedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @updatedAt @db.Timestamptz(6) device device @relation(fields: [deviceid], references: [id], onDelete: Cascade) @@unique([deviceid, password], map: "idx_18062_autoauth_deviceid_password_key") @@ -59,8 +59,8 @@ model device { uuid String @unique(map: "idx_18069_device_uuid_key") @db.VarChar(191) name String? @db.VarChar(191) accountid String? @db.VarChar(191) - createdat DateTime @default(now()) @db.Timestamptz(6) - updatedat DateTime @db.Timestamptz(6) + createdat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @db.Timestamptz(6) + updatedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @updatedAt @db.Timestamptz(6) password String? @db.VarChar(191) passwordhint String? @db.VarChar(191) namespace String? @unique(map: "idx_18069_device_namespace_key") @db.VarChar(191) @@ -77,8 +77,8 @@ model kvstore { key String @db.VarChar(191) value Json @db.Json creatorip String? @default("") @db.VarChar(191) - createdat DateTime @default(now()) @db.Timestamptz(6) - updatedat DateTime @db.Timestamptz(6) + createdat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @db.Timestamptz(6) + updatedat DateTime @default(dbgenerated("timezone('Asia/Shanghai', now())")) @updatedAt @db.Timestamptz(6) device device @relation(fields: [deviceid], references: [id], onDelete: Cascade) @@id([deviceid, key], map: "idx_18075_primary") diff --git a/routes/accounts.js b/routes/accounts.js index 54895db..679b669 100644 --- a/routes/accounts.js +++ b/routes/accounts.js @@ -232,10 +232,10 @@ router.get("/oauth/:provider/callback", async (req, res) => { // 2. 使用访问令牌获取用户信息 let userResponse; - // Casdoor 支持两种方式:Authorization Bearer 或 accessToken 查询参数 + // Casdoor 支持两种方式:Authorization Bearer 或 accesstoken 查询参数 if (provider === 'stcn') { const url = new URL(providerConfig.userInfoURL); - url.searchParams.set('accessToken', tokenData.access_token); + url.searchParams.set('accesstoken', tokenData.access_token); userResponse = await fetch(url, {headers: {"Accept": "application/json"}}); } else { userResponse = await fetch(providerConfig.userInfoURL, { @@ -256,14 +256,14 @@ router.get("/oauth/:provider/callback", async (req, res) => { providerId: String(userData.id), email: userData.email, name: userData.name || userData.login, - avatarUrl: userData.avatar_url, + avatarurl: userData.avatar_url, }; } else if (provider === "zerocat") { normalizedUser = { providerId: userData.openid, email: userData.email_verified ? userData.email : null, name: userData.nickname || userData.username, - avatarUrl: userData.avatar, + avatarurl: userData.avatar, }; } else if (provider === "hly") { // 厚浪云(Logto)标准OIDC用户信息 @@ -271,7 +271,7 @@ router.get("/oauth/:provider/callback", async (req, res) => { providerId: userData.sub, email: userData.email_verified ? userData.email : null, name: userData.name || userData.preferred_username || userData.nickname, - avatarUrl: userData.picture, + avatarurl: userData.picture, }; } else if (provider === "stcn") { // STCN(Casdoor)标准OIDC用户信息 @@ -279,7 +279,7 @@ router.get("/oauth/:provider/callback", async (req, res) => { providerId: userData.sub, email: userData.email_verified ? userData.email : userData.email || null, name: userData.name || userData.preferred_username || userData.nickname, - avatarUrl: userData.picture, + avatarurl: userData.picture, }; } else if (provider === "dlass") { // Dlass(Casdoor)标准OIDC用户信息 @@ -287,7 +287,7 @@ router.get("/oauth/:provider/callback", async (req, res) => { providerId: userData.sub, email: userData.email_verified ? userData.email : userData.email || null, name: userData.name || userData.preferred_username || userData.nickname, - avatarUrl: userData.picture, + avatarurl: userData.picture, }; } @@ -316,25 +316,25 @@ router.get("/oauth/:provider/callback", async (req, res) => { data: { email: normalizedUser.email || account.email, name: normalizedUser.name || account.name, - avatarUrl: normalizedUser.avatarUrl || account.avatarUrl, + avatarurl: normalizedUser.avatarurl || account.avatarurl, providerData: userData, - //refreshToken: tokenData.refresh_token || account.refreshToken, - updatedAt: new Date(), + //refreshtoken: tokenData.refresh_token || account.refreshtoken, + updatedat: new Date(), }, }); } else { // 创建新账户 - const accessToken = generateAccessToken(); + const accesstoken = generateAccessToken(); account = await prisma.account.create({ data: { provider, providerId: normalizedUser.providerId, email: normalizedUser.email, name: normalizedUser.name, - avatarUrl: normalizedUser.avatarUrl, + avatarurl: normalizedUser.avatarurl, providerData: userData, - accessToken, - //refreshToken: tokenData.refresh_token, + accesstoken, + //refreshtoken: tokenData.refresh_token, }, }); } @@ -345,9 +345,9 @@ router.get("/oauth/:provider/callback", async (req, res) => { // 6. 重定向到前端根路径,携带JWT token const frontendBaseUrl = process.env.FRONTEND_URL || "http://localhost:5173"; const callbackUrl = new URL(frontendBaseUrl); - callbackUrl.searchParams.append("access_token", tokens.accessToken); - callbackUrl.searchParams.append("refresh_token", tokens.refreshToken); - callbackUrl.searchParams.append("expires_in", tokens.accessTokenExpiresIn); + callbackUrl.searchParams.append("access_token", tokens.accesstoken); + callbackUrl.searchParams.append("refresh_token", tokens.refreshtoken); + callbackUrl.searchParams.append("expires_in", tokens.accesstokenExpiresIn); callbackUrl.searchParams.append("provider", provider); // 附带展示信息,便于前端显示品牌与名称 const pconf = oauthProviders[provider] || {}; @@ -392,7 +392,7 @@ router.get("/profile", jwtAuth, async (req, res, next) => { id: true, uuid: true, name: true, - createdAt: true, + createdat: true, }, }, }, @@ -421,9 +421,9 @@ router.get("/profile", jwtAuth, async (req, res, next) => { providerInfo, email: account.email, name: account.name, - avatarUrl: account.avatarUrl, + avatarurl: account.avatarurl, devices: account.devices, - createdAt: account.createdAt, + createdat: account.createdat, }, }); } catch (error) { @@ -487,7 +487,7 @@ router.post("/devices/bind", jwtAuth, async (req, res, next) => { success: true, message: "设备绑定成功", data: { - deviceId: updatedDevice.id, + deviceid: updatedDevice.id, uuid: updatedDevice.uuid, name: updatedDevice.name, }, @@ -592,8 +592,8 @@ router.get("/devices", jwtAuth, async (req, res, next) => { uuid: true, name: true, namespace: true, - createdAt: true, - updatedAt: true, + createdat: true, + updatedat: true, }, }, }, @@ -627,8 +627,8 @@ router.get("/device/:uuid/account", async (req, res, next) => { id: true, provider: true, name: true, - avatarUrl: true, - createdAt: true, + avatarurl: true, + createdat: true, }, }, }, @@ -654,8 +654,8 @@ router.get("/device/:uuid/account", async (req, res, next) => { id: device.account.id, provider: device.account.provider, name: device.account.name, - avatarUrl: device.account.avatarUrl, - bindTime: device.updatedAt, // 绑定时间 + avatarurl: device.account.avatarurl, + bindTime: device.updatedat, // 绑定时间 }, }); } catch (error) { @@ -690,8 +690,8 @@ router.post("/refresh", async (req, res, next) => { success: true, message: "令牌刷新成功", data: { - access_token: result.accessToken, - expires_in: result.accessTokenExpiresIn, + access_token: result.accesstoken, + expires_in: result.accesstokenExpiresIn, account: result.account, }, }); @@ -780,14 +780,14 @@ router.get("/token-info", jwtAuth, async (req, res, next) => { data: { accountId: account.id, tokenType: decoded.type || 'legacy', - tokenVersion: decoded.tokenVersion || account.tokenVersion, + tokenversion: decoded.tokenversion || account.tokenversion, issuedAt: new Date(decoded.iat * 1000), expiresAt: new Date(decoded.exp * 1000), expiresIn: expiresIn, isExpired: expiresIn <= 0, isLegacyToken: res.locals.isLegacyToken || false, - hasRefreshToken: !!account.refreshToken, - refreshTokenExpiry: account.refreshTokenExpiry, + hasRefreshToken: !!account.refreshtoken, + refreshtokenExpiry: account.refreshtokenExpiry, }, }); } catch (error) { diff --git a/routes/apps.js b/routes/apps.js index 78c3200..4d3b295 100644 --- a/routes/apps.js +++ b/routes/apps.js @@ -25,15 +25,15 @@ router.get( return next(errors.createError(404, "设备不存在")); } - const installations = await prisma.appInstall.findMany({ - where: {deviceId: device.id}, + const installations = await prisma.appinstall.findMany({ + where: {deviceid: device.id}, }); const apps = installations.map(install => ({ appId: install.appId, token: install.token, note: install.note, - installedAt: install.createdAt, + installedAt: install.createdat, })); return res.json({ @@ -60,9 +60,9 @@ router.post( const token = crypto.randomBytes(32).toString("hex"); // 创建安装记录 - const installation = await prisma.appInstall.create({ + const installation = await prisma.appinstall.create({ data: { - deviceId: device.id, + deviceid: device.id, appId: appId, token, note: note || null, @@ -75,7 +75,7 @@ router.post( token: installation.token, note: installation.note, name: installation.note, // 备注同时作为名称返回 - installedAt: installation.createdAt, + installedAt: installation.createdat, }); }) ); @@ -91,7 +91,7 @@ router.delete( const device = res.locals.device; const {installId} = req.params; - const installation = await prisma.appInstall.findUnique({ + const installation = await prisma.appinstall.findUnique({ where: {id: installId}, }); @@ -100,11 +100,11 @@ router.delete( } // 确保安装记录属于当前设备 - if (installation.deviceId !== device.id) { + if (installation.deviceid !== device.id) { return next(errors.createError(403, "无权操作此安装记录")); } - await prisma.appInstall.delete({ + await prisma.appinstall.delete({ where: {id: installation.id}, }); @@ -135,8 +135,8 @@ router.get( } // 获取该设备的所有应用安装记录(即token) - const installations = await prisma.appInstall.findMany({ - where: {deviceId: device.id}, + const installations = await prisma.appinstall.findMany({ + where: {deviceid: device.id}, orderBy: {installedAt: 'desc'}, }); @@ -235,22 +235,22 @@ router.post( // 根据自动授权配置创建 AppInstall const token = crypto.randomBytes(32).toString("hex"); - const installation = await prisma.appInstall.create({ + const installation = await prisma.appinstall.create({ data: { - deviceId: device.id, + deviceid: device.id, appId: appId, token, note: null, - isReadOnly: matchedAutoAuth.isReadOnly, - deviceType: matchedAutoAuth.deviceType, + isreadonly: matchedAutoAuth.isreadonly, + devicetype: matchedAutoAuth.devicetype, }, }); return res.status(201).json({ success: true, token: installation.token, - deviceType: installation.deviceType, - isReadOnly: installation.isReadOnly, + devicetype: installation.devicetype, + isreadonly: installation.isreadonly, installedAt: installation.installedAt, }); }) @@ -272,7 +272,7 @@ router.post( } // 查找 token 对应的应用安装记录 - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: {token}, include: { device: true, @@ -284,15 +284,15 @@ router.post( } // 验证 token 类型是否为 student - if (!['student', 'parent'].includes(appInstall.deviceType)) { + if (!['student', 'parent'].includes(appInstall.devicetype)) { return next(errors.createError(403, "只有学生和家长类型的 token 可以设置名称")); } // 读取设备的 classworks-list-main 键值 const kvRecord = await prisma.kvstore.findUnique({ where: { - deviceId_key: { - deviceId: appInstall.deviceId, + deviceid_key: { + deviceid: appInstall.deviceid, key: 'classworks-list-main', }, }, @@ -321,17 +321,17 @@ router.post( } // 更新 AppInstall 的 note 字段 - const updatedInstall = await prisma.appInstall.update({ + const updatedInstall = await prisma.appinstall.update({ where: {id: appInstall.id}, - data: {note: appInstall.deviceType === 'parent' ? `${name} 家长` : name}, + data: {note: appInstall.devicetype === 'parent' ? `${name} 家长` : name}, }); return res.json({ success: true, token: updatedInstall.token, name: updatedInstall.note, - deviceType: updatedInstall.deviceType, - updatedAt: updatedInstall.updatedAt, + devicetype: updatedInstall.devicetype, + updatedat: updatedInstall.updatedat, }); }) ); @@ -352,7 +352,7 @@ router.post( } // 查找 token 对应的应用安装记录 - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: {token}, include: { device: true, @@ -364,12 +364,12 @@ router.post( } // 验证 token 类型是否为 teacher - if (appInstall.deviceType !== 'teacher') { + if (appInstall.devicetype !== 'teacher') { return next(errors.createError(403, "只有教师类型的 token 可以使用此接口")); } // 更新 AppInstall 的 note 字段为教师名称 - const updatedInstall = await prisma.appInstall.update({ + const updatedInstall = await prisma.appinstall.update({ where: {id: appInstall.id}, data: {note: name}, }); @@ -378,8 +378,8 @@ router.post( success: true, token: updatedInstall.token, name: updatedInstall.note, - deviceType: updatedInstall.deviceType, - updatedAt: updatedInstall.updatedAt, + devicetype: updatedInstall.devicetype, + updatedat: updatedInstall.updatedat, }); }) ); @@ -396,7 +396,7 @@ router.put( const {note} = req.body; // 查找 token 对应的应用安装记录 - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: {token}, }); @@ -405,7 +405,7 @@ router.put( } // 更新 AppInstall 的 note 字段 - const updatedInstall = await prisma.appInstall.update({ + const updatedInstall = await prisma.appinstall.update({ where: {id: appInstall.id}, data: {note: note || null}, }); @@ -414,7 +414,7 @@ router.put( success: true, token: updatedInstall.token, note: updatedInstall.note, - updatedAt: updatedInstall.updatedAt, + updatedat: updatedInstall.updatedat, }); }) ); diff --git a/routes/auto-auth.js b/routes/auto-auth.js index 4cadadb..9de9b49 100644 --- a/routes/auto-auth.js +++ b/routes/auto-auth.js @@ -31,8 +31,8 @@ router.get( } const autoAuths = await prisma.autoAuth.findMany({ - where: {deviceId: device.id}, - orderBy: {createdAt: 'desc'}, + where: {deviceid: device.id}, + orderBy: {createdat: 'desc'}, }); // 返回配置,智能处理密码显示 @@ -44,10 +44,10 @@ router.get( id: auth.id, password: isHashedPassword ? null : auth.password, // 哈希密码不返回 isLegacyHash: isHashedPassword, // 标记是否为旧的哈希密码 - deviceType: auth.deviceType, - isReadOnly: auth.isReadOnly, - createdAt: auth.createdAt, - updatedAt: auth.updatedAt, + devicetype: auth.devicetype, + isreadonly: auth.isreadonly, + createdat: auth.createdat, + updatedat: auth.updatedat, }; }); @@ -61,7 +61,7 @@ router.get( /** * POST /auto-auth/devices/:uuid/auth-configs * 创建新的自动授权配置 (需要 JWT 认证,且设备必须绑定到该账户) - * Body: { password?: string, deviceType?: string, isReadOnly?: boolean } + * Body: { password?: string, devicetype?: string, isreadonly?: boolean } */ router.post( "/devices/:uuid/auth-configs", @@ -69,7 +69,7 @@ router.post( errors.catchAsync(async (req, res, next) => { const {uuid} = req.params; const account = res.locals.account; - const {password, deviceType, isReadOnly} = req.body; + const {password, devicetype, isreadonly} = req.body; // 查找设备并验证是否属于当前账户 const device = await prisma.device.findUnique({ @@ -85,9 +85,9 @@ router.post( return next(errors.createError(403, "该设备未绑定到您的账户")); } - // 验证 deviceType 如果提供的话 + // 验证 devicetype 如果提供的话 const validDeviceTypes = ['teacher', 'student', 'classroom', 'parent']; - if (deviceType && !validDeviceTypes.includes(deviceType)) { + if (devicetype && !validDeviceTypes.includes(devicetype)) { return next(errors.createError(400, `设备类型必须是以下之一: ${validDeviceTypes.join(', ')}`)); } @@ -96,7 +96,7 @@ router.post( // 查询该设备的所有自动授权配置,本地检查是否存在相同密码 const allAuths = await prisma.autoAuth.findMany({ - where: {deviceId: device.id}, + where: {deviceid: device.id}, }); const existingAuth = allAuths.find(auth => auth.password === plainPassword); @@ -108,10 +108,10 @@ router.post( // 创建新的自动授权配置(密码明文存储) const autoAuth = await prisma.autoAuth.create({ data: { - deviceId: device.id, + deviceid: device.id, password: plainPassword, - deviceType: deviceType || null, - isReadOnly: isReadOnly || false, + devicetype: devicetype || null, + isreadonly: isreadonly || false, }, }); @@ -120,9 +120,9 @@ router.post( config: { id: autoAuth.id, password: autoAuth.password, // 返回明文密码 - deviceType: autoAuth.deviceType, - isReadOnly: autoAuth.isReadOnly, - createdAt: autoAuth.createdAt, + devicetype: autoAuth.devicetype, + isreadonly: autoAuth.isreadonly, + createdat: autoAuth.createdat, }, }); }) @@ -130,7 +130,7 @@ router.post( /** * PUT /auto-auth/devices/:uuid/auth-configs/:configId * 更新自动授权配置 (需要 JWT 认证,且设备必须绑定到该账户) - * Body: { password?: string, deviceType?: string, isReadOnly?: boolean } + * Body: { password?: string, devicetype?: string, isreadonly?: boolean } */ router.put( "/devices/:uuid/auth-configs/:configId", @@ -138,7 +138,7 @@ router.put( errors.catchAsync(async (req, res, next) => { const {uuid, configId} = req.params; const account = res.locals.account; - const {password, deviceType, isReadOnly} = req.body; + const {password, devicetype, isreadonly} = req.body; // 查找设备并验证是否属于当前账户 const device = await prisma.device.findUnique({ @@ -164,13 +164,13 @@ router.put( } // 确保配置属于当前设备 - if (autoAuth.deviceId !== device.id) { + if (autoAuth.deviceid !== device.id) { return next(errors.createError(403, "无权操作此配置")); } - // 验证 deviceType + // 验证 devicetype const validDeviceTypes = ['teacher', 'student', 'classroom', 'parent']; - if (deviceType && !validDeviceTypes.includes(deviceType)) { + if (devicetype && !validDeviceTypes.includes(devicetype)) { return next(errors.createError(400, `设备类型必须是以下之一: ${validDeviceTypes.join(', ')}`)); } @@ -183,7 +183,7 @@ router.put( // 查询该设备的所有配置,本地检查新密码是否与其他配置冲突 const allAuths = await prisma.autoAuth.findMany({ - where: {deviceId: device.id}, + where: {deviceid: device.id}, }); const conflictAuth = allAuths.find(auth => @@ -197,12 +197,12 @@ router.put( updateData.password = plainPassword; } - if (deviceType !== undefined) { - updateData.deviceType = deviceType || null; + if (devicetype !== undefined) { + updateData.devicetype = devicetype || null; } - if (isReadOnly !== undefined) { - updateData.isReadOnly = isReadOnly; + if (isreadonly !== undefined) { + updateData.isreadonly = isreadonly; } // 更新配置 @@ -216,9 +216,9 @@ router.put( config: { id: updatedAuth.id, password: updatedAuth.password, // 返回明文密码 - deviceType: updatedAuth.deviceType, - isReadOnly: updatedAuth.isReadOnly, - updatedAt: updatedAuth.updatedAt, + devicetype: updatedAuth.devicetype, + isreadonly: updatedAuth.isreadonly, + updatedat: updatedAuth.updatedat, }, }); }) @@ -259,7 +259,7 @@ router.delete( } // 确保配置属于当前设备 - if (autoAuth.deviceId !== device.id) { + if (autoAuth.deviceid !== device.id) { return next(errors.createError(403, "无权操作此配置")); } @@ -334,7 +334,7 @@ router.put( uuid: updatedDevice.uuid, name: updatedDevice.name, namespace: updatedDevice.namespace, - updatedAt: updatedDevice.updatedAt, + updatedat: updatedDevice.updatedat, }, }); }) diff --git a/routes/device-auth.js b/routes/device-auth.js index 6a448d4..f332151 100644 --- a/routes/device-auth.js +++ b/routes/device-auth.js @@ -62,7 +62,7 @@ router.post( } // 验证token是否有效(检查数据库) - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: {token}, }); @@ -193,7 +193,7 @@ router.get( exists: true, has_token: status.hasToken, expires_in: Math.floor((status.expiresAt - Date.now()) / 1000), - created_at: status.createdAt, + created_at: status.createdat, }); }) ); diff --git a/routes/device.js b/routes/device.js index ab6da5c..64de961 100644 --- a/routes/device.js +++ b/routes/device.js @@ -9,17 +9,17 @@ const router = Router(); /** * 为新设备创建默认的自动登录配置 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID */ -async function createDefaultAutoAuth(deviceId) { +async function createDefaultAutoAuth(deviceid) { try { // 创建默认的自动授权配置:不需要密码、类型是classroom(一体机) await prisma.autoAuth.create({ data: { - deviceId: deviceId, + deviceid: deviceid, password: null, // 无密码 - deviceType: "classroom", // 一体机类型 - isReadOnly: false, // 非只读 + devicetype: "classroom", // 一体机类型 + isreadonly: false, // 非只读 }, }); } catch (error) { @@ -90,7 +90,7 @@ router.post( uuid: device.uuid, name: device.name, namespace: device.namespace, - createdAt: device.createdAt, + createdat: device.createdat, }, }); } catch (error) { @@ -117,7 +117,7 @@ router.get( id: true, name: true, email: true, - avatarUrl: true, + avatarurl: true, }, }, }, @@ -132,13 +132,13 @@ router.get( uuid: device.uuid, name: device.name, hasPassword: !!device.password, - passwordHint: device.passwordHint, - createdAt: device.createdAt, + 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, + avatarurl: device.account.avatarurl, } : null, isBoundToAccount: !!device.account, namespace: device.namespace, @@ -172,7 +172,7 @@ router.put( uuid: updatedDevice.uuid, name: updatedDevice.name, hasPassword: !!updatedDevice.password, - passwordHint: updatedDevice.passwordHint, + passwordhint: updatedDevice.passwordhint, }, }); }) diff --git a/routes/kv-token.js b/routes/kv-token.js index 70c1d50..2b5dce6 100644 --- a/routes/kv-token.js +++ b/routes/kv-token.js @@ -28,11 +28,11 @@ router.get( "/_info", tokenReadLimiter, errors.catchAsync(async (req, res, next) => { - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; // 获取设备信息,包含关联的账号 const device = await prisma.device.findUnique({ - where: { id: deviceId }, + where: { id: deviceid }, include: { account: true, }, @@ -47,8 +47,8 @@ router.get( device: { id: device.id, name: device.name, - createdAt: device.createdAt, - updatedAt: device.updatedAt, + createdat: device.createdat, + updatedat: device.updatedat, }, }; @@ -65,7 +65,7 @@ router.get( response.account = { id: device.account.id, name: device.account.name, - avatarUrl: device.account.avatarUrl, + avatarurl: device.account.avatarurl, }; } @@ -82,10 +82,10 @@ router.get( tokenReadLimiter, errors.catchAsync(async (req, res, next) => { const token = res.locals.token; - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; // 查找当前 token 对应的应用安装记录 - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: { token }, include: { device: { @@ -107,11 +107,11 @@ router.get( success: true, token: appInstall.token, appId: appInstall.appId, - deviceType: appInstall.deviceType, - isReadOnly: appInstall.isReadOnly, + devicetype: appInstall.devicetype, + isreadonly: appInstall.isreadonly, note: appInstall.note, installedAt: appInstall.installedAt, - updatedAt: appInstall.updatedAt, + updatedat: appInstall.updatedat, device: { id: appInstall.device.id, uuid: appInstall.device.uuid, @@ -130,7 +130,7 @@ router.get( "/_keys", tokenReadLimiter, errors.catchAsync(async (req, res) => { - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { sortBy, sortDir, limit, skip } = req.query; // 构建选项 @@ -141,7 +141,7 @@ router.get( skip: skip ? parseInt(skip) : 0, }; - const keys = await kvStore.listKeysOnly(deviceId, options); + const keys = await kvStore.listKeysOnly(deviceid, options); const totalRows = keys.length; // 构建响应对象 @@ -181,7 +181,7 @@ router.get( "/", tokenReadLimiter, errors.catchAsync(async (req, res) => { - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { sortBy, sortDir, limit, skip } = req.query; // 构建选项 @@ -192,8 +192,8 @@ router.get( skip: skip ? parseInt(skip) : 0, }; - const keys = await kvStore.list(deviceId, options); - const totalRows = await kvStore.count(deviceId); + const keys = await kvStore.list(deviceid, options); + const totalRows = await kvStore.count(deviceid); // 构建响应对象 const response = { @@ -227,10 +227,10 @@ router.get( "/:key", tokenReadLimiter, errors.catchAsync(async (req, res, next) => { - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { key } = req.params; - const value = await kvStore.get(deviceId, key); + const value = await kvStore.get(deviceid, key); if (value === null) { return next( @@ -250,10 +250,10 @@ router.get( "/:key/metadata", tokenReadLimiter, errors.catchAsync(async (req, res, next) => { - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { key } = req.params; - const metadata = await kvStore.getMetadata(deviceId, key); + const metadata = await kvStore.getMetadata(deviceid, key); if (!metadata) { return next( errors.createError(404, `未找到键名为 '${key}' 的记录`) @@ -272,11 +272,11 @@ router.post( tokenBatchLimiter, errors.catchAsync(async (req, res, next) => { // 检查token是否为只读 - if (res.locals.appInstall?.isReadOnly) { + if (res.locals.appInstall?.isreadonly) { return next(errors.createError(403, "当前token为只读模式,无法修改数据")); } - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const data = req.body; if (!data || Object.keys(data).length === 0) { @@ -289,7 +289,7 @@ router.post( } // 获取客户端IP - const creatorIp = + const creatorip = req.headers["x-forwarded-for"] || req.connection.remoteAddress || req.socket.remoteAddress || @@ -297,13 +297,13 @@ router.post( ""; // 使用优化的批量upsert方法 - const { results, errors: errorList } = await kvStore.batchUpsert(deviceId, data, creatorIp); + const { results, errors: errorList } = await kvStore.batchUpsert(deviceid, data, creatorip); return res.status(200).json({ code: 200, message: "批量导入成功", data: { - deviceId, + deviceid, summary: { total: Object.keys(data).length, successful: results.length, @@ -328,11 +328,11 @@ router.post( tokenWriteLimiter, errors.catchAsync(async (req, res, next) => { // 检查token是否为只读 - if (res.locals.appInstall?.isReadOnly) { + if (res.locals.appInstall?.isreadonly) { return next(errors.createError(403, "当前token为只读模式,无法修改数据")); } - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { key } = req.params; let value = req.body; @@ -351,14 +351,14 @@ router.post( } // 获取客户端IP - const creatorIp = + const creatorip = req.headers["x-forwarded-for"] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket?.remoteAddress || ""; - const result = await kvStore.upsert(deviceId, key, value, creatorIp); + const result = await kvStore.upsert(deviceid, key, value, creatorip); // 广播单个键的变更 const uuid = res.locals.device?.uuid; @@ -366,16 +366,16 @@ router.post( broadcastKeyChanged(uuid, { key: result.key, action: "upsert", - created: result.createdAt.getTime() === result.updatedAt.getTime(), - updatedAt: result.updatedAt, + created: result.createdat.getTime() === result.updatedat.getTime(), + updatedat: result.updatedat, }); } return res.status(200).json({ - deviceId: result.deviceId, + deviceid: result.deviceid, key: result.key, - created: result.createdAt.getTime() === result.updatedAt.getTime(), - updatedAt: result.updatedAt, + created: result.createdat.getTime() === result.updatedat.getTime(), + updatedat: result.updatedat, }); }) ); @@ -389,14 +389,14 @@ router.delete( tokenDeleteLimiter, errors.catchAsync(async (req, res, next) => { // 检查token是否为只读 - if (res.locals.appInstall?.isReadOnly) { + if (res.locals.appInstall?.isreadonly) { return next(errors.createError(403, "当前token为只读模式,无法修改数据")); } - const deviceId = res.locals.deviceId; + const deviceid = res.locals.deviceid; const { key } = req.params; - const result = await kvStore.delete(deviceId, key); + const result = await kvStore.delete(deviceid, key); if (!result) { return next( diff --git a/utils/deviceCodeStore.js b/utils/deviceCodeStore.js index 5e5c173..dd87fe1 100644 --- a/utils/deviceCodeStore.js +++ b/utils/deviceCodeStore.js @@ -7,7 +7,7 @@ class DeviceCodeStore { constructor() { - // 存储结构: { deviceCode: { token: string, expiresAt: number, createdAt: number } } + // 存储结构: { deviceCode: { token: string, expiresAt: number, createdat: number } } this.store = new Map(); // 默认过期时间: 15分钟 @@ -44,7 +44,7 @@ class DeviceCodeStore { this.store.set(deviceCode, { token: null, expiresAt: now + this.expirationTime, - createdAt: now, + createdat: now, }); return deviceCode; @@ -143,7 +143,7 @@ class DeviceCodeStore { return { hasToken: !!entry.token, expiresAt: entry.expiresAt, - createdAt: entry.createdAt, + createdat: entry.createdat, }; } diff --git a/utils/jwt.js b/utils/jwt.js index ed2da2e..a671327 100644 --- a/utils/jwt.js +++ b/utils/jwt.js @@ -61,7 +61,7 @@ export function generateAccountToken(account) { provider: account.provider, email: account.email, name: account.name, - avatarUrl: account.avatarUrl, + avatarurl: account.avatarurl, }); } diff --git a/utils/kvStore.js b/utils/kvStore.js index 29d5bdb..f9c594c 100644 --- a/utils/kvStore.js +++ b/utils/kvStore.js @@ -4,15 +4,15 @@ import {keysTotal} from "./metrics.js"; class KVStore { /** * 通过设备ID和键名获取值 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {string} key - 键名 * @returns {object|null} 键对应的值或null */ - async get(deviceId, key) { + async get(deviceid, key) { const item = await prisma.kvstore.findUnique({ where: { - deviceId_key: { - deviceId: deviceId, + deviceid_key: { + deviceid: deviceid, key: key, }, }, @@ -22,24 +22,24 @@ class KVStore { /** * 获取键的完整信息(包括元数据) - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {string} key - 键名 * @returns {object|null} 键的完整信息或null */ - async getMetadata(deviceId, key) { + async getMetadata(deviceid, key) { const item = await prisma.kvstore.findUnique({ where: { - deviceId_key: { - deviceId: deviceId, + deviceid_key: { + deviceid: deviceid, key: key, }, }, select: { key: true, - deviceId: true, - creatorIp: true, - createdAt: true, - updatedAt: true, + deviceid: true, + creatorip: true, + createdat: true, + updatedat: true, }, }); @@ -47,41 +47,41 @@ class KVStore { // 转换为更友好的格式 return { - deviceId: item.deviceId, + deviceid: item.deviceid, key: item.key, metadata: { - creatorIp: item.creatorIp, - createdAt: item.createdAt, - updatedAt: item.updatedAt, + creatorip: item.creatorip, + createdat: item.createdat, + updatedat: item.updatedat, }, }; } /** * 在指定设备下创建或更新键值 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {string} key - 键名 * @param {object} value - 键值 - * @param {string} creatorIp - 创建者IP,可选 + * @param {string} creatorip - 创建者IP,可选 * @returns {object} 创建或更新的记录 */ - async upsert(deviceId, key, value, creatorIp = "") { + async upsert(deviceid, key, value, creatorip = "") { const item = await prisma.kvstore.upsert({ where: { - deviceId_key: { - deviceId: deviceId, + deviceid_key: { + deviceid: deviceid, key: key, }, }, update: { value, - ...(creatorIp && {creatorIp}), + ...(creatorip && {creatorip}), }, create: { - deviceId: deviceId, + deviceid: deviceid, key: key, value, - creatorIp, + creatorip: creatorip, }, }); @@ -91,23 +91,23 @@ class KVStore { // 返回带有设备ID和原始键的结果 return { - deviceId, + deviceid, key, value: item.value, - creatorIp: item.creatorIp, - createdAt: item.createdAt, - updatedAt: item.updatedAt, + creatorip: item.creatorip, + createdat: item.createdat, + updatedat: item.updatedat, }; } /** * 批量创建或更新键值对(优化性能) - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {object} data - 键值对数据 {key1: value1, key2: value2, ...} - * @param {string} creatorIp - 创建者IP,可选 + * @param {string} creatorip - 创建者IP,可选 * @returns {object} {results: Array, errors: Array} */ - async batchUpsert(deviceId, data, creatorIp = "") { + async batchUpsert(deviceid, data, creatorip = "") { const results = []; const errors = []; @@ -117,28 +117,28 @@ class KVStore { try { const item = await tx.kvstore.upsert({ where: { - deviceId_key: { - deviceId: deviceId, + deviceid_key: { + deviceid: deviceid, key: key, }, }, update: { value, - ...(creatorIp && {creatorIp}), + ...(creatorip && {creatorip: creatorip}), }, create: { - deviceId: deviceId, + deviceid: deviceid, key: key, value, - creatorIp, + creatorip: creatorip, }, }); results.push({ key: item.key, - created: item.createdAt.getTime() === item.updatedAt.getTime(), - createdAt: item.createdAt, - updatedAt: item.updatedAt, + created: item.createdat.getTime() === item.updatedat.getTime(), + createdat: item.createdat, + updatedat: item.updatedat, }); } catch (error) { errors.push({ @@ -158,16 +158,16 @@ class KVStore { /** * 通过设备ID和键名删除 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {string} key - 键名 * @returns {object|null} 删除的记录或null */ - async delete(deviceId, key) { + async delete(deviceid, key) { try { const item = await prisma.kvstore.delete({ where: { - deviceId_key: { - deviceId: deviceId, + deviceid_key: { + deviceid: deviceid, key: key, }, }, @@ -177,7 +177,7 @@ class KVStore { const totalKeys = await prisma.kvstore.count(); keysTotal.set(totalKeys); - return item ? {...item, deviceId, key} : null; + return item ? {...item, deviceid, key} : null; } catch (error) { // 忽略记录不存在的错误 if (error.code === "P2025") { @@ -189,11 +189,11 @@ class KVStore { /** * 列出指定设备下的所有键名及其元数据 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {object} options - 选项参数 * @returns {Array} 键名和元数据数组 */ - async list(deviceId, options = {}) { + async list(deviceid, options = {}) { const {sortBy = "key", sortDir = "asc", limit = 100, skip = 0} = options; // 构建排序条件 @@ -203,14 +203,14 @@ class KVStore { // 查询设备的所有键 const items = await prisma.kvstore.findMany({ where: { - deviceId: deviceId, + deviceid: deviceid, }, select: { - deviceId: true, + deviceid: true, key: true, - creatorIp: true, - createdAt: true, - updatedAt: true, + creatorip: true, + createdat: true, + updatedat: true, value: false, }, orderBy, @@ -220,23 +220,23 @@ class KVStore { // 处理结果 return items.map((item) => ({ - deviceId: item.deviceId, + deviceid: item.deviceid, key: item.key, metadata: { - creatorIp: item.creatorIp, - createdAt: item.createdAt, - updatedAt: item.updatedAt, + creatorip: item.creatorip, + createdat: item.createdat, + updatedat: item.updatedat, }, })); } /** * 获取指定设备下的键名列表(不包括内容) - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @param {object} options - 查询选项 * @returns {Array} 键名列表 */ - async listKeysOnly(deviceId, options = {}) { + async listKeysOnly(deviceid, options = {}) { const {sortBy = "key", sortDir = "asc", limit = 100, skip = 0} = options; // 构建排序条件 @@ -246,7 +246,7 @@ class KVStore { // 查询设备的所有键,只选择键名 const items = await prisma.kvstore.findMany({ where: { - deviceId: deviceId, + deviceid: deviceid, }, select: { key: true, @@ -262,13 +262,13 @@ class KVStore { /** * 统计指定设备下的键值对数量 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @returns {number} 键值对数量 */ - async count(deviceId) { + async count(deviceid) { const count = await prisma.kvstore.count({ where: { - deviceId: deviceId, + deviceid: deviceid, }, }); return count; @@ -276,32 +276,32 @@ class KVStore { /** * 获取指定设备的统计信息 - * @param {number} deviceId - 设备ID + * @param {number} deviceid - 设备ID * @returns {object} 统计信息 */ - async getStats(deviceId) { + async getStats(deviceid) { const [totalKeys, oldestKey, newestKey] = await Promise.all([ prisma.kvstore.count({ - where: { deviceId }, + where: { deviceid }, }), prisma.kvstore.findFirst({ - where: { deviceId }, - orderBy: { createdAt: "asc" }, - select: { createdAt: true, key: true }, + where: { deviceid }, + orderBy: { createdat: "asc" }, + select: { createdat: true, key: true }, }), prisma.kvstore.findFirst({ - where: { deviceId }, - orderBy: { updatedAt: "desc" }, - select: { updatedAt: true, key: true }, + where: { deviceid }, + orderBy: { updatedat: "desc" }, + select: { updatedat: true, key: true }, }), ]); return { totalKeys, oldestKey: oldestKey?.key, - oldestCreatedAt: oldestKey?.createdAt, + oldestCreatedAt: oldestKey?.createdat, newestKey: newestKey?.key, - newestUpdatedAt: newestKey?.updatedAt, + newestUpdatedAt: newestKey?.updatedat, }; } } diff --git a/utils/siteinfo.js b/utils/siteinfo.js index d4278d2..3acf267 100644 --- a/utils/siteinfo.js +++ b/utils/siteinfo.js @@ -46,8 +46,8 @@ async function getSystemDeviceId() { */ export const initReadme = async () => { try { - const deviceId = await getSystemDeviceId(); - const storedValue = await kvStore.get(deviceId, "info"); + const deviceid = await getSystemDeviceId(); + const storedValue = await kvStore.get(deviceid, "info"); // 合并默认值与存储值,确保结构完整 readmeValue = { @@ -82,8 +82,8 @@ export const getReadmeValue = () => { */ export const updateReadmeValue = async (newValue) => { try { - const deviceId = await getSystemDeviceId(); - await kvStore.upsert(deviceId, "info", newValue); + const deviceid = await getSystemDeviceId(); + await kvStore.upsert(deviceid, "info", newValue); readmeValue = { ...defaultReadme, ...newValue, diff --git a/utils/socket.js b/utils/socket.js index 7f812db..b2161d5 100644 --- a/utils/socket.js +++ b/utils/socket.js @@ -33,7 +33,7 @@ const clientHints = new ClientHints(); const onlineMap = new Map(); // 在线 token 映射:token -> Set (用于指标统计) const onlineTokens = new Map(); -// 令牌信息缓存:token -> {appId, isReadOnly, deviceType, note, deviceUuid, deviceName} +// 令牌信息缓存:token -> {appId, isreadonly, devicetype, note, deviceUuid, deviceName} const tokenInfoCache = new Map(); // 事件历史记录:每个设备最多保存1000条事件记录 const eventHistory = new Map(); // uuid -> Array @@ -132,7 +132,7 @@ export function initSocket(server) { try { const token = payload?.token || payload?.apptoken; if (typeof token !== "string" || token.length === 0) return; - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: { token }, include: { device: { select: { uuid: true } } }, }); @@ -175,9 +175,9 @@ export function initSocket(server) { devices: historyData, timestamp: new Date().toISOString(), requestedBy: { - deviceType: socket.data.tokenInfo?.deviceType, + devicetype: socket.data.tokenInfo?.devicetype, deviceName: socket.data.tokenInfo?.deviceName, - isReadOnly: socket.data.tokenInfo?.isReadOnly + isreadonly: socket.data.tokenInfo?.isreadonly } }); @@ -219,7 +219,7 @@ export function initSocket(server) { // 检查只读权限 const tokenInfo = socket.data.tokenInfo; - if (tokenInfo?.isReadOnly) { + if (tokenInfo?.isreadonly) { socket.emit("event-error", { reason: "readonly_token_cannot_send_events" }); return; } @@ -243,9 +243,9 @@ export function initSocket(server) { senderId: socket.id, senderInfo: { appId: tokenInfo?.appId, - deviceType: tokenInfo?.deviceType, + devicetype: tokenInfo?.devicetype, deviceName: tokenInfo?.note, - isReadOnly: tokenInfo?.isReadOnly || false, + isreadonly: tokenInfo?.isreadonly || false, note: tokenInfo?.note } }; @@ -385,7 +385,7 @@ function removeTokenConnection(token, socketId) { /** * 广播某设备下 KV 键已变更 * @param {string} uuid 设备 uuid - * @param {object} payload { key, action: 'upsert'|'delete'|'batch', updatedAt?, created? } + * @param {object} payload { key, action: 'upsert'|'delete'|'batch', updatedat?, created? } */ export function broadcastKeyChanged(uuid, payload) { if (!io || !uuid) return; @@ -400,9 +400,9 @@ export function broadcastKeyChanged(uuid, payload) { senderId: "realtime", senderInfo: { appId: "5c2a54d553951a37b47066ead68c8642", - deviceType: "server", + devicetype: "server", deviceName: "realtime", - isReadOnly: false, + isreadonly: false, note: "Database realtime sync" } }; @@ -443,9 +443,9 @@ export function broadcastDeviceEvent(uuid, type, content = null, senderId = "sys senderId, senderInfo: { appId: "system", - deviceType: "system", + devicetype: "system", deviceName: "System", - isReadOnly: false, + isreadonly: false, note: "System broadcast" } }; @@ -549,7 +549,7 @@ export default { */ async function joinByToken(socket, token) { try { - const appInstall = await prisma.appInstall.findUnique({ + const appInstall = await prisma.appinstall.findUnique({ where: { token }, include: { device: { @@ -576,8 +576,8 @@ async function joinByToken(socket, token) { // 缓存令牌信息,使用拼接后的设备名称 const tokenInfo = { appId: appInstall.appId, - isReadOnly: appInstall.isReadOnly, - deviceType: appInstall.deviceType, + isreadonly: appInstall.isreadonly, + devicetype: appInstall.devicetype, note: appInstall.note, deviceUuid: uuid, deviceName: finalDeviceName, // 使用拼接后的设备名称 @@ -600,8 +600,8 @@ async function joinByToken(socket, token) { uuid, token, tokenInfo: { - isReadOnly: tokenInfo.isReadOnly, - deviceType: tokenInfo.deviceType, + isreadonly: tokenInfo.isreadonly, + devicetype: tokenInfo.devicetype, deviceName: tokenInfo.deviceName, userAgent: userAgent } diff --git a/utils/tokenManager.js b/utils/tokenManager.js index 742648c..12bcd45 100644 --- a/utils/tokenManager.js +++ b/utils/tokenManager.js @@ -50,8 +50,8 @@ export function generateAccessToken(account) { provider: account.provider, email: account.email, name: account.name, - avatarUrl: account.avatarUrl, - tokenVersion: account.tokenVersion || 1, + avatarurl: account.avatarurl, + tokenversion: account.tokenversion || 1, }; return jwt.sign(payload, signKey, { @@ -71,7 +71,7 @@ export function generateRefreshToken(account) { const payload = { type: 'refresh', accountId: account.id, - tokenVersion: account.tokenVersion || 1, + tokenversion: account.tokenversion || 1, // 添加随机字符串增加安全性 jti: crypto.randomBytes(16).toString('hex'), }; @@ -134,39 +134,39 @@ export function verifyRefreshToken(token) { * 生成令牌对(访问令牌 + 刷新令牌) */ export async function generateTokenPair(account) { - const accessToken = generateAccessToken(account); - const refreshToken = generateRefreshToken(account); + const accesstoken = generateAccessToken(account); + const refreshtoken = generateRefreshToken(account); // 计算刷新令牌过期时间 - const refreshTokenExpiry = new Date(); + const refreshtokenExpiry = new Date(); const expiresInMs = parseExpirationToMs(REFRESH_TOKEN_EXPIRES_IN); - refreshTokenExpiry.setTime(refreshTokenExpiry.getTime() + expiresInMs); + refreshtokenExpiry.setTime(refreshtokenExpiry.getTime() + expiresInMs); // 更新数据库中的刷新令牌 await prisma.account.update({ where: {id: account.id}, data: { - refreshToken, - refreshTokenExpiry, - updatedAt: new Date(), + refreshtoken, + refreshtokenExpiry, + updatedat: new Date(), }, }); return { - accessToken, - refreshToken, - accessTokenExpiresIn: ACCESS_TOKEN_EXPIRES_IN, - refreshTokenExpiresIn: REFRESH_TOKEN_EXPIRES_IN, + accesstoken, + refreshtoken, + accesstokenExpiresIn: ACCESS_TOKEN_EXPIRES_IN, + refreshtokenExpiresIn: REFRESH_TOKEN_EXPIRES_IN, }; } /** * 刷新访问令牌 */ -export async function refreshAccessToken(refreshToken) { +export async function refreshAccessToken(refreshtoken) { try { // 验证刷新令牌 - const decoded = verifyRefreshToken(refreshToken); + const decoded = verifyRefreshToken(refreshtoken); // 从数据库获取账户信息 const account = await prisma.account.findUnique({ @@ -178,17 +178,17 @@ export async function refreshAccessToken(refreshToken) { } // 验证刷新令牌是否匹配 - if (account.refreshToken !== refreshToken) { + if (account.refreshtoken !== refreshtoken) { throw new Error('Invalid refresh token'); } // 验证刷新令牌是否过期 - if (account.refreshTokenExpiry && account.refreshTokenExpiry < new Date()) { + if (account.refreshtokenExpiry && account.refreshtokenExpiry < new Date()) { throw new Error('Refresh token expired'); } // 验证令牌版本 - if (account.tokenVersion !== decoded.tokenVersion) { + if (account.tokenversion !== decoded.tokenversion) { throw new Error('Token version mismatch'); } @@ -196,14 +196,14 @@ export async function refreshAccessToken(refreshToken) { const newAccessToken = generateAccessToken(account); return { - accessToken: newAccessToken, - accessTokenExpiresIn: ACCESS_TOKEN_EXPIRES_IN, + accesstoken: newAccessToken, + accesstokenExpiresIn: ACCESS_TOKEN_EXPIRES_IN, account: { id: account.id, provider: account.provider, email: account.email, name: account.name, - avatarUrl: account.avatarUrl, + avatarurl: account.avatarurl, }, }; } catch (error) { @@ -218,10 +218,10 @@ export async function revokeAllTokens(accountId) { await prisma.account.update({ where: {id: accountId}, data: { - tokenVersion: {increment: 1}, - refreshToken: null, - refreshTokenExpiry: null, - updatedAt: new Date(), + tokenversion: {increment: 1}, + refreshtoken: null, + refreshtokenExpiry: null, + updatedat: new Date(), }, }); } @@ -233,9 +233,9 @@ export async function revokeRefreshToken(accountId) { await prisma.account.update({ where: {id: accountId}, data: { - refreshToken: null, - refreshTokenExpiry: null, - updatedAt: new Date(), + refreshtoken: null, + refreshtokenExpiry: null, + updatedat: new Date(), }, }); } @@ -283,7 +283,7 @@ export async function validateAccountToken(decoded) { } // 验证令牌版本 - if (account.tokenVersion !== decoded.tokenVersion) { + if (account.tokenversion !== decoded.tokenversion) { throw new Error('Token version mismatch'); }