优化后端鉴权与日志安全

This commit is contained in:
yml2213
2026-05-26 08:21:11 +08:00
parent 851d1d1efc
commit dea3023825
35 changed files with 402 additions and 185 deletions
@@ -43,6 +43,7 @@ import {
normalizeActor,
parseTaskContext,
} from "./kuaishou-cloud/task-context.js";
import type { TaskRow } from "../../types/repository-rows.js";
export {
isKuaishouCloudBindUrlFresh,
@@ -58,7 +59,7 @@ export {
resolvePersistedCloudtentaclesContextWithFallback,
} from "./kuaishou-cloud/cloudtentacles-context.js";
export async function ensureTaskClaimLink(task) {
export async function ensureTaskClaimLink(task: TaskRow) {
const tokenStatus = String(task?.primary_claim_token_status || "").trim();
const token = String(
task?.primary_claim_token || task?.claim_token || ""
@@ -82,7 +83,7 @@ export async function ensureTaskClaimLink(task) {
}
export async function prepareKuaishouCloudFulfillmentTask(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {
@@ -246,7 +247,7 @@ export async function prepareKuaishouCloudFulfillmentTask(
bindUrl: preparedBinding.bindUrl,
bindPreparedAt: now,
bindExpiresAt: resolveKuaishouCloudBindUrlExpiresAt(now),
bindProbeAt: null,
bindProbeAt: null as null,
bindProbeStatus: "pending",
bindProbeMessage: "",
roleName: "",
@@ -256,9 +257,9 @@ export async function prepareKuaishouCloudFulfillmentTask(
status: "pending",
name: "",
rid: "",
refreshedAt: null,
refreshedAt: null as null,
errorMessage: "",
rawInfo: null,
rawInfo: null as null,
},
purchase: {
...flowWithResolvedBinding.purchase,
@@ -312,7 +313,7 @@ export async function prepareKuaishouCloudFulfillmentTask(
}
export async function refreshKuaishouCloudTaskBindUrl(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {
@@ -413,7 +414,7 @@ export async function refreshKuaishouCloudTaskBindUrl(
bindUrl: preparedBinding.bindUrl,
bindPreparedAt: now,
bindExpiresAt: resolveKuaishouCloudBindUrlExpiresAt(now),
bindProbeAt: null,
bindProbeAt: null as null,
bindProbeStatus: "pending",
bindProbeMessage: "",
roleName:
@@ -485,7 +486,7 @@ export async function refreshKuaishouCloudTaskBindUrl(
}
export async function probeKuaishouCloudTaskBindUrl(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {
@@ -503,7 +504,7 @@ export async function probeKuaishouCloudTaskBindUrl(
return {
task,
flow,
probe: null,
probe: null as null,
};
}
@@ -518,7 +519,7 @@ export async function probeKuaishouCloudTaskBindUrl(
return {
task,
flow,
probe: null,
probe: null as null,
};
}
@@ -582,7 +583,7 @@ export async function probeKuaishouCloudTaskBindUrl(
* @param {{ taskContext?: any, flow?: any, now?: string, actor?: any, error?: unknown }} [input]
*/
async function markKuaishouCloudBindUrlRefreshFailed(
task,
task: TaskRow,
{ taskContext, flow, now, actor, error }: JsonObject = {}
) {
const errorMessage =
@@ -648,7 +649,7 @@ async function markKuaishouCloudBindUrlRefreshFailed(
}
export async function refreshKuaishouCloudTaskRoleInfo(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {
@@ -11,8 +11,8 @@ import {
import { KUAISHOU_CLOUD_FIXED_VN_KEY, type JsonObject } from "./domain.js";
export function resolveKuaishouCloudBindingResources(
flow,
{ skuItems = [], knapsackItems = [] } = {}
flow: JsonObject,
{ skuItems = [], knapsackItems = [] }: { skuItems?: unknown[], knapsackItems?: unknown[] } = {}
) {
const normalizedSkuItems = Array.isArray(skuItems)
? skuItems.filter(isCloudSkuLikeItem)
@@ -70,7 +70,7 @@ export function resolveKuaishouCloudBindingResources(
};
}
export function resolveKuaishouCloudVnKeyCandidates(_input = {}) {
export function resolveKuaishouCloudVnKeyCandidates(_input: JsonObject = {}) {
return [KUAISHOU_CLOUD_FIXED_VN_KEY];
}
@@ -159,7 +159,7 @@ export async function prepareKuaishouCloudBindResourceWithFallback(input: JsonOb
);
}
function collectKuaishouCloudNameCandidates(flow) {
function collectKuaishouCloudNameCandidates(flow: JsonObject) {
return Array.from(
new Set(
[
@@ -171,10 +171,10 @@ function collectKuaishouCloudNameCandidates(flow) {
);
}
function findCloudItemByNames(items, nameCandidates, preferredId = 0) {
function findCloudItemByNames(items: JsonObject[], nameCandidates: string[], preferredId = 0) {
const normalizedItems = Array.isArray(items) ? items : [];
const normalizedNames = nameCandidates
.map((item) => ({
.map((item: string) => ({
raw: String(item || "").trim(),
normalized: normalizeProductName(item),
}))
@@ -182,34 +182,34 @@ function findCloudItemByNames(items, nameCandidates, preferredId = 0) {
if (normalizedNames.length === 0 || normalizedItems.length === 0) {
return preferredId > 0
? normalizedItems.find((item) => Number(item.id || 0) === preferredId) ||
? normalizedItems.find((item: JsonObject) => Number(item.id || 0) === preferredId) ||
null
: null;
}
if (preferredId > 0) {
const preferred =
normalizedItems.find((item) => Number(item.id || 0) === preferredId) ||
normalizedItems.find((item: JsonObject) => Number(item.id || 0) === preferredId) ||
null;
if (preferred) {
return preferred;
}
}
const exactMatches = normalizedItems.filter((item) => {
const exactMatches = normalizedItems.filter((item: JsonObject) => {
const itemName = normalizeProductName(item.name);
return normalizedNames.some(
(candidate) => candidate.normalized === itemName
(candidate: { normalized: string }) => candidate.normalized === itemName
);
});
if (exactMatches.length > 0) {
return exactMatches[0];
}
const partialMatches = normalizedItems.filter((item) => {
const partialMatches = normalizedItems.filter((item: JsonObject) => {
const itemName = normalizeProductName(item.name);
return normalizedNames.some(
(candidate) =>
(candidate: { normalized: string }) =>
itemName.includes(candidate.normalized) ||
candidate.normalized.includes(itemName)
);
@@ -224,13 +224,15 @@ function findCloudItemByNames(items, nameCandidates, preferredId = 0) {
return null;
}
function isCloudSkuLikeItem(item) {
return Boolean(item) && typeof item === "object" && Number(item.id || 0) > 0;
function isCloudSkuLikeItem(item: unknown): item is JsonObject {
const current = item && typeof item === "object" ? item as JsonObject : {};
return Number(current.id || 0) > 0;
}
function isRecoverableKuaishouCloudVnKeyError(error) {
const errorCode = String(error?.errorCode || error?.code || "").trim();
const errorMessage = String(error?.message || "").trim();
function isRecoverableKuaishouCloudVnKeyError(error: unknown) {
const current = error && typeof error === "object" ? error as JsonObject : {};
const errorCode = String(current.errorCode || current.code || "").trim();
const errorMessage = String(current.message || "").trim();
return (
errorCode === "cloudtentacles_vn_bind_url_failed" &&
errorMessage.includes("不支持的游戏类型")
@@ -45,7 +45,7 @@ export function resolvePersistedCloudtentaclesContext(sourceKey = "default") {
*/
export function resolvePersistedCloudtentaclesContextWithFallback(
primarySourceKey = "default",
fallbacks = []
fallbacks: unknown[] = []
) {
const candidates = [
String(primarySourceKey || "default").trim() || "default",
@@ -8,12 +8,13 @@ export const KUAISHOU_CLOUD_FIXED_VN_KEY = "1";
export type JsonObject = Record<string, any>;
export function isKuaishouCloudTask(task) {
return String(task?.executor_key || "").trim() === "kuaishou_ct_assisted";
export function isKuaishouCloudTask(task: unknown) {
const source = task && typeof task === "object" ? task as JsonObject : {};
return String(source.executor_key || "").trim() === "kuaishou_ct_assisted";
}
export function normalizeKuaishouCloudFlow(value) {
const source = value && typeof value === "object" ? value : {};
export function normalizeKuaishouCloudFlow(value: unknown) {
const source: JsonObject = value && typeof value === "object" ? value as JsonObject : {};
const binding =
source.binding && typeof source.binding === "object" ? source.binding : {};
const role =
@@ -129,8 +130,8 @@ export function normalizeKuaishouCloudFlow(value) {
};
}
export function normalizeKuaishouCloudRoleInfo(value) {
const rawInfo = value && typeof value === "object" ? value : null;
export function normalizeKuaishouCloudRoleInfo(value: unknown) {
const rawInfo: JsonObject | null = value && typeof value === "object" ? value as JsonObject : null;
const nestedBindInfo =
rawInfo?.sBindInfo && typeof rawInfo.sBindInfo === "object"
? rawInfo.sBindInfo
@@ -157,15 +158,15 @@ export function normalizeKuaishouCloudRoleInfo(value) {
};
}
export function maskPhone(value) {
export function maskPhone(value: unknown) {
return maskPhoneValue(value);
}
export function maskCode(value) {
export function maskCode(value: unknown) {
return maskCodeValue(value);
}
export function resolveKuaishouCloudBindUrlExpiresAt(preparedAt) {
export function resolveKuaishouCloudBindUrlExpiresAt(preparedAt: unknown) {
const preparedTime = Date.parse(String(preparedAt || ""));
if (!Number.isFinite(preparedTime)) {
return null;
@@ -176,7 +177,7 @@ export function resolveKuaishouCloudBindUrlExpiresAt(preparedAt) {
return new Date(preparedTime + Math.max(1, ttlSeconds) * 1000).toISOString();
}
export function isKuaishouCloudBindUrlFresh(flow, now = new Date()) {
export function isKuaishouCloudBindUrlFresh(flow: unknown, now = new Date()) {
const normalizedFlow = normalizeKuaishouCloudFlow(flow);
if (!normalizedFlow.binding.bindUrl) {
return false;
@@ -195,7 +196,7 @@ export function isKuaishouCloudBindUrlFresh(flow, now = new Date()) {
return expiresTime > now.getTime();
}
export function normalizeStringArray(value) {
export function normalizeStringArray(value: unknown) {
if (Array.isArray(value)) {
return value.map((v) => String(v || "").trim()).filter(Boolean);
}
@@ -1,14 +1,18 @@
import { parseTaskContext as parseTaskContextValue } from "../../../utils/task-json.js";
import type { TaskRow } from "../../../types/repository-rows.js";
export function normalizeActor(actor) {
type JsonObject = Record<string, any>;
export function normalizeActor(actor: unknown) {
if (!actor || typeof actor !== "object") {
return null;
}
const source = String(actor.source || "").trim();
const userId = Number(actor.userId || 0) || 0;
const username = String(actor.username || "").trim();
const role = String(actor.role || "").trim();
const current = actor as JsonObject;
const source = String(current.source || "").trim();
const userId = Number(current.userId || 0) || 0;
const username = String(current.username || "").trim();
const role = String(current.role || "").trim();
if (!source && !userId && !username && !role) {
return null;
@@ -22,19 +26,19 @@ export function normalizeActor(actor) {
};
}
export function parseTaskContext(task) {
export function parseTaskContext(task: Partial<TaskRow> | null | undefined) {
return parseTaskContextValue(task);
}
export function getTaskClaimExpiresAt(task) {
export function getTaskClaimExpiresAt(task: Partial<TaskRow> | null | undefined) {
return task?.claim_expires_at || task?.primary_claim_expires_at || null;
}
export function isClaimExpired(expiredAt) {
export function isClaimExpired(expiredAt: unknown) {
if (!expiredAt) {
return false;
}
const timestamp = new Date(expiredAt).getTime();
const timestamp = new Date(expiredAt instanceof Date ? expiredAt : String(expiredAt || "")).getTime();
return Number.isFinite(timestamp) && timestamp <= Date.now();
}
@@ -20,9 +20,10 @@ import {
} from "./domain.js";
import { resolvePersistedCloudtentaclesContextWithFallback } from "./cloudtentacles-context.js";
import { normalizeActor, parseTaskContext } from "./task-context.js";
import type { TaskRow } from "../../../types/repository-rows.js";
export async function dispatchKuaishouCloudFulfillmentTask(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {
@@ -157,7 +158,7 @@ export async function dispatchKuaishouCloudFulfillmentTask(
}
export async function returnKuaishouCloudFulfillmentTask(
task,
task: TaskRow,
options: JsonObject = {}
) {
if (!isKuaishouCloudTask(task)) {