This commit is contained in:
张成
2026-03-24 16:07:02 +08:00
commit aa8eaa6ccd
121 changed files with 34042 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
const crypto = require("crypto");
const baseModel = require("../../middleware/baseModel");
const { op } = baseModel;
const MAX_TOKENS_PER_USER = 5;
function hashPlainToken(plain) {
return crypto.createHash("sha256").update(plain, "utf8").digest("hex");
}
function generatePlainToken() {
return `waw_${crypto.randomBytes(24).toString("hex")}`;
}
/** 当前时间在 [start,end] 内且 status=active 的订阅 */
async function findActiveSubscriptionForUser(userId) {
const now = new Date();
return baseModel.biz_subscription.findOne({
where: {
user_id: userId,
status: "active",
start_time: { [op.lte]: now },
end_time: { [op.gte]: now },
},
order: [["id", "DESC"]],
});
}
async function createToken(body) {
const { user_id, token_name, expire_at } = body;
if (!user_id || !expire_at) throw new Error("缺少 user_id 或 expire_at");
const u = await baseModel.biz_user.findByPk(user_id);
if (!u) throw new Error("用户不存在");
if (u.status !== "active") throw new Error("用户已禁用");
const activeCount = await baseModel.biz_api_token.count({
where: { user_id, status: "active" },
});
if (activeCount >= MAX_TOKENS_PER_USER) {
throw new Error(`单用户最多 ${MAX_TOKENS_PER_USER} 个有效 Token`);
}
const sub = await findActiveSubscriptionForUser(user_id);
const plan_id = sub ? sub.plan_id : null;
const plain = generatePlainToken();
const token_hash = hashPlainToken(plain);
const row = await baseModel.biz_api_token.create({
user_id,
plan_id,
token_name: token_name || "default",
token_hash,
status: "active",
expire_at,
});
return {
row,
plain_token: plain,
warn: sub ? null : "当前无生效中的订阅,鉴权将失败",
};
}
async function revokeToken(body) {
const id = body.id;
if (id == null) throw new Error("缺少 id");
const row = await baseModel.biz_api_token.findByPk(id);
if (!row) throw new Error("Token 不存在");
await row.update({ status: "revoked" });
return row;
}
async function revokeAllForUser(userId) {
if (userId == null) throw new Error("缺少 user_id");
const [n] = await baseModel.biz_api_token.update(
{ status: "revoked" },
{ where: { user_id: userId, status: "active" } }
);
return n;
}
module.exports = {
hashPlainToken,
createToken,
revokeToken,
revokeAllForUser,
findActiveSubscriptionForUser,
MAX_TOKENS_PER_USER,
};