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

规范代码格式

This commit is contained in:
Sunwuyuan 2025-11-16 16:15:05 +08:00
parent 4ec10acfcf
commit c545612c9c
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
34 changed files with 3982 additions and 3965 deletions

4
app.js
View File

@ -1,7 +1,7 @@
import "./utils/instrumentation.js"; import "./utils/instrumentation.js";
// import createError from "http-errors"; // import createError from "http-errors";
import express from "express"; import express from "express";
import { join, dirname } from "path"; import {dirname, join} from "path";
import {fileURLToPath} from "url"; import {fileURLToPath} from "url";
// import cookieParser from "cookie-parser"; // import cookieParser from "cookie-parser";
import logger from "morgan"; import logger from "morgan";
@ -16,10 +16,10 @@ import deviceAuthRouter from "./routes/device-auth.js";
import accountsRouter from "./routes/accounts.js"; import accountsRouter from "./routes/accounts.js";
import autoAuthRouter from "./routes/auto-auth.js"; import autoAuthRouter from "./routes/auto-auth.js";
import {register} from "./utils/metrics.js"; import {register} from "./utils/metrics.js";
import cors from "cors";
var app = express(); var app = express();
import cors from "cors";
app.options("/{*path}", cors()); app.options("/{*path}", cors());
app.use( app.use(
cors({ cors({

View File

@ -10,8 +10,6 @@
* 或配置为可执行chmod +x cli/get-token.js && ./cli/get-token.js * 或配置为可执行chmod +x cli/get-token.js && ./cli/get-token.js
*/ */
import readline from 'readline';
// 配置 // 配置
const CONFIG = { const CONFIG = {
// API服务器地址 // API服务器地址

View File

@ -6,7 +6,7 @@
* 适用于只需要账户验证的接口 * 适用于只需要账户验证的接口
*/ */
import { verifyAccessToken, validateAccountToken, generateAccessToken } from "../utils/tokenManager.js"; import {generateAccessToken, validateAccountToken, verifyAccessToken} from "../utils/tokenManager.js";
import {verifyToken} from "../utils/jwt.js"; import {verifyToken} from "../utils/jwt.js";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";

View File

@ -56,7 +56,6 @@ export const prepareTokenForRateLimit = (req, res, next) => {
}; };
// 认证相关路由限速器(防止暴力破解) // 认证相关路由限速器(防止暴力破解)
export const authLimiter = rateLimit({ export const authLimiter = rateLimit({
windowMs: 30 * 60 * 1000, // 30分钟 windowMs: 30 * 60 * 1000, // 30分钟

View File

@ -109,6 +109,7 @@ export const extractDeviceInfo = async (req,res,next) => {
res.locals.deviceId = device.id; res.locals.deviceId = device.id;
next(); next();
} }
/** /**
* 从请求中提取UUID * 从请求中提取UUID
*/ */

View File

@ -2,7 +2,7 @@
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>登录失败</title> <title>登录失败</title>
<style> <style>
* { * {
@ -50,9 +50,15 @@
} }
@keyframes shake { @keyframes shake {
0%, 100% { transform: translateX(0); } 0%, 100% {
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); } transform: translateX(0);
20%, 40%, 60%, 80% { transform: translateX(5px); } }
10%, 30%, 50%, 70%, 90% {
transform: translateX(-5px);
}
20%, 40%, 60%, 80% {
transform: translateX(5px);
}
} }
h1 { h1 {
@ -123,7 +129,7 @@
<div class="container"> <div class="container">
<div class="error-icon"> <div class="error-icon">
<svg fill="none" viewBox="0 0 24 24"> <svg fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> <path d="M6 18L18 6M6 6l12 12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</div> </div>
@ -134,7 +140,7 @@
<div class="error-code" id="errorCode"></div> <div class="error-code" id="errorCode"></div>
</div> </div>
<a href="javascript:history.back()" class="retry-btn">返回重试</a> <a class="retry-btn" href="javascript:history.back()">返回重试</a>
<button class="close-btn" onclick="window.close()">关闭窗口</button> <button class="close-btn" onclick="window.close()">关闭窗口</button>
<div class="help-text"> <div class="help-text">

View File

@ -2,7 +2,7 @@
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>登录成功</title> <title>登录成功</title>
<style> <style>
* { * {
@ -135,7 +135,7 @@
<div class="container"> <div class="container">
<div class="success-icon"> <div class="success-icon">
<svg fill="none" viewBox="0 0 24 24"> <svg fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /> <path d="M5 13l4 4L19 7" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</div> </div>

View File

@ -1,8 +1,8 @@
import {Router} from "express"; import {Router} from "express";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
import crypto from "crypto"; import crypto from "crypto";
import { oauthProviders, getCallbackURL, generateState } from "../config/oauth.js"; import {generateState, getCallbackURL, oauthProviders} from "../config/oauth.js";
import { generateAccountToken, generateTokenPair, refreshAccessToken, revokeAllTokens, revokeRefreshToken } from "../utils/jwt.js"; import {generateTokenPair, refreshAccessToken, revokeAllTokens, revokeRefreshToken} from "../utils/jwt.js";
import {jwtAuth} from "../middleware/jwt-auth.js"; import {jwtAuth} from "../middleware/jwt-auth.js";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";

View File

@ -1,13 +1,12 @@
import {Router} from "express"; import {Router} from "express";
const router = Router();
import {uuidAuth} from "../middleware/uuidAuth.js"; import {uuidAuth} from "../middleware/uuidAuth.js";
import { jwtAuth } from "../middleware/jwt-auth.js";
import { kvTokenAuth } from "../middleware/kvTokenAuth.js";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
import crypto from "crypto"; import crypto from "crypto";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";
import {verifyDevicePassword} from "../utils/crypto.js"; import {verifyDevicePassword} from "../utils/crypto.js";
const router = Router();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
/** /**
@ -217,7 +216,7 @@ router.post(
} }
} catch (err) { } catch (err) {
// 如果验证失败,继续尝试下一个 // 如果验证失败,继续尝试下一个
continue;
} }
} }
} }

View File

@ -1,9 +1,10 @@
import {Router} from "express"; import {Router} from "express";
const router = Router();
import {jwtAuth} from "../middleware/jwt-auth.js"; import {jwtAuth} from "../middleware/jwt-auth.js";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";
const router = Router();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
/** /**
@ -127,7 +128,8 @@ router.post(
}, },
}); });
}) })
);/** );
/**
* PUT /auto-auth/devices/:uuid/auth-configs/:configId * PUT /auto-auth/devices/:uuid/auth-configs/:configId
* 更新自动授权配置 (需要 JWT 认证且设备必须绑定到该账户) * 更新自动授权配置 (需要 JWT 认证且设备必须绑定到该账户)
* Body: { password?: string, deviceType?: string, isReadOnly?: boolean } * Body: { password?: string, deviceType?: string, isReadOnly?: boolean }

View File

@ -7,7 +7,6 @@ const router = Router();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
/** /**
* POST /device/code * POST /device/code
* 生成设备授权码 * 生成设备授权码

View File

@ -1,13 +1,12 @@
import {Router} from "express"; import {Router} from "express";
const router = Router(); import {extractDeviceInfo} from "../middleware/uuidAuth.js";
import { uuidAuth, extractDeviceInfo } from "../middleware/uuidAuth.js";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
import crypto from "crypto";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";
import { hashPassword, verifyDevicePassword } from "../utils/crypto.js";
import {getOnlineDevices} from "../utils/socket.js"; import {getOnlineDevices} from "../utils/socket.js";
import {registeredDevicesTotal} from "../utils/metrics.js"; import {registeredDevicesTotal} from "../utils/metrics.js";
const router = Router();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
/** /**
@ -147,7 +146,8 @@ router.get(
namespace: device.namespace, namespace: device.namespace,
}); });
}) })
);/** );
/**
* PUT /devices/:uuid/name * PUT /devices/:uuid/name
* 设置设备名称 (需要UUID认证) * 设置设备名称 (需要UUID认证)
*/ */
@ -181,7 +181,6 @@ router.put(
); );
/** /**
* GET /devices/online * GET /devices/online
* 查询在线设备WebSocket 已连接 * 查询在线设备WebSocket 已连接

View File

@ -1,4 +1,5 @@
import {Router} from "express"; import {Router} from "express";
var router = Router(); var router = Router();
/* GET home page. */ /* GET home page. */

View File

@ -1,18 +1,19 @@
import {Router} from "express"; import {Router} from "express";
const router = Router();
import kvStore from "../utils/kvStore.js"; import kvStore from "../utils/kvStore.js";
import {broadcastKeyChanged} from "../utils/socket.js"; import {broadcastKeyChanged} from "../utils/socket.js";
import {kvTokenAuth} from "../middleware/kvTokenAuth.js"; import {kvTokenAuth} from "../middleware/kvTokenAuth.js";
import { import {
tokenReadLimiter, prepareTokenForRateLimit,
tokenWriteLimiter,
tokenDeleteLimiter,
tokenBatchLimiter, tokenBatchLimiter,
prepareTokenForRateLimit tokenDeleteLimiter,
tokenReadLimiter,
tokenWriteLimiter
} from "../middleware/rateLimiter.js"; } from "../middleware/rateLimiter.js";
import errors from "../utils/errors.js"; import errors from "../utils/errors.js";
import {PrismaClient} from "@prisma/client"; import {PrismaClient} from "@prisma/client";
const router = Router();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
// 使用KV专用token认证 // 使用KV专用token认证

View File

@ -1,4 +1,5 @@
import dotenv from "dotenv"; import dotenv from "dotenv";
dotenv.config(); dotenv.config();
export const siteKey = process.env.SITE_KEY || ""; export const siteKey = process.env.SITE_KEY || "";

View File

@ -5,6 +5,7 @@ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import {BatchSpanProcessor} from "@opentelemetry/sdk-trace-base"; import {BatchSpanProcessor} from "@opentelemetry/sdk-trace-base";
import {resourceFromAttributes} from "@opentelemetry/resources"; import {resourceFromAttributes} from "@opentelemetry/resources";
import {SemanticResourceAttributes} from "@opentelemetry/semantic-conventions"; import {SemanticResourceAttributes} from "@opentelemetry/semantic-conventions";
if (process.env.AXIOM_TOKEN && process.env.AXIOM_DATASET) { if (process.env.AXIOM_TOKEN && process.env.AXIOM_DATASET) {
// Initialize OTLP trace exporter with the endpoint URL and headers // Initialize OTLP trace exporter with the endpoint URL and headers
// Initialize OTLP trace exporter with the endpoint URL and headers // Initialize OTLP trace exporter with the endpoint URL and headers

View File

@ -1,11 +1,11 @@
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { import {
generateAccessToken, generateAccessToken,
verifyAccessToken,
generateTokenPair, generateTokenPair,
refreshAccessToken, refreshAccessToken,
revokeAllTokens, revokeAllTokens,
revokeRefreshToken, revokeRefreshToken,
verifyAccessToken,
} from './tokenManager.js'; } from './tokenManager.js';
// JWT 配置(支持 HS256 与 RS256 // JWT 配置(支持 HS256 与 RS256

View File

@ -2,6 +2,7 @@ import { PrismaClient } from "@prisma/client";
import {keysTotal} from "./metrics.js"; import {keysTotal} from "./metrics.js";
const prisma = new PrismaClient(); const prisma = new PrismaClient();
class KVStore { class KVStore {
/** /**
* 通过设备ID和键名获取值 * 通过设备ID和键名获取值

View File

@ -46,14 +46,16 @@ export function initSocket(server) {
// 仅允许通过 query.token/apptoken 加入 // 仅允许通过 query.token/apptoken 加入
const qToken = socket.handshake?.query?.token || socket.handshake?.query?.apptoken; const qToken = socket.handshake?.query?.token || socket.handshake?.query?.apptoken;
if (qToken && typeof qToken === "string") { if (qToken && typeof qToken === "string") {
joinByToken(socket, qToken).catch(() => {}); joinByToken(socket, qToken).catch(() => {
});
} }
// 客户端使用 KV token 加入房间 // 客户端使用 KV token 加入房间
socket.on("join-token", (payload) => { socket.on("join-token", (payload) => {
const token = payload?.token || payload?.apptoken; const token = payload?.token || payload?.apptoken;
if (typeof token === "string" && token.length > 0) { if (typeof token === "string" && token.length > 0) {
joinByToken(socket, token).catch(() => {}); joinByToken(socket, token).catch(() => {
});
} }
}); });

View File

@ -259,11 +259,16 @@ function parseExpirationToMs(expiresIn) {
const unit = match[2]; const unit = match[2];
switch (unit) { switch (unit) {
case 's': return value * 1000; case 's':
case 'm': return value * 60 * 1000; return value * 1000;
case 'h': return value * 60 * 60 * 1000; case 'm':
case 'd': return value * 24 * 60 * 60 * 1000; return value * 60 * 1000;
default: throw new Error('Invalid time unit'); case 'h':
return value * 60 * 60 * 1000;
case 'd':
return value * 24 * 60 * 60 * 1000;
default:
throw new Error('Invalid time unit');
} }
} }

View File

@ -11,5 +11,7 @@
<h1>Classworks 服务端</h1> <h1>Classworks 服务端</h1>
<p>服务运行中</p> <p>服务运行中</p>
</body> </body>
<script>
window.open('https://kv.houlang.cloud')
</script>
</html> </html>