35 lines
1.9 KiB
TypeScript
35 lines
1.9 KiB
TypeScript
import cloud from "@lafjs/cloud";
|
|
import { checkClientVersion, configUnavailable, openidWhitelist, shouldCheckPlayerVersion } from "@/versionPolicy";
|
|
|
|
// Laf detects this signature by function.length: keep exactly two non-default parameters.
|
|
export default async function (ctx: FunctionContext, next: (context: FunctionContext) => Promise<any>) {
|
|
const method = String(ctx.method || ctx.request?.method || "").toUpperCase();
|
|
if (method === "OPTIONS" || method === "CALL") return await next(ctx);
|
|
// Set by Laf's router, not by a client-provided body/header. Preserve nested function names.
|
|
const functionName = ctx.__function_name || ctx.request?.path?.replace(/^\//, "");
|
|
if (!functionName) return configUnavailable();
|
|
const params = method === "GET" || method === "HEAD" ? ctx.query : ctx.body;
|
|
const rejection = checkClientVersion(functionName, params?.version);
|
|
if (rejection?.errorCode === "CLIENT_UPDATE_REQUIRED" && openidWhitelist.length > 0) {
|
|
// Login has no trusted openid yet. It checks after code2session, before any user writes.
|
|
if (functionName === "login") return await next(ctx);
|
|
// Never trust a request's openid/uid for whitelist membership. Resolve the login token.
|
|
const token = params?.token;
|
|
if (typeof token !== "string" || !token) return await next(ctx);
|
|
let openid: unknown;
|
|
try {
|
|
const db = cloud.database();
|
|
const main = await db.collection("users").where({ token }).getOne();
|
|
const user = main.data || (await db.collection("usersAd").where({ token }).getOne()).data;
|
|
openid = user?.openid;
|
|
} catch {
|
|
// A failed lookup must not silently let a targeted old client into business logic.
|
|
return configUnavailable();
|
|
}
|
|
// Unauthenticated requests continue to the endpoint's existing authentication checks.
|
|
if (!shouldCheckPlayerVersion(openid)) return await next(ctx);
|
|
}
|
|
if (rejection) return rejection;
|
|
return await next(ctx);
|
|
}
|