Files
console-dev/tests/fixtures/api-server.mjs
T
2026-11-06 00:04:38 +08:00

269 lines
8.5 KiB
JavaScript

import { createServer } from "node:http";
const token = "e2e-session-token";
const account = {
id: 1,
username: "audit-user",
email: "audit@example.invalid",
credit: "100.00",
};
const initialKeys = Array.from({ length: 28 }, (_, index) => ({
id: index + 1,
name:
index < 25
? `audit-${String(index + 1).padStart(2, "0")}`
: `other-${index + 1}`,
public_key: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestPublicKey${index + 1}`,
finger_print: `SHA256:fixture-${index + 1}`,
}));
let options = {};
let requests = [];
let paid = false;
let keys = initialKeys.map((key) => ({ ...key }));
function reply(response, data = {}, extra = {}, httpStatus = 200) {
response.writeHead(httpStatus, { "Content-Type": "application/json" });
response.end(JSON.stringify({ status: httpStatus, msg: "", data, ...extra }));
}
const server = createServer(async (request, response) => {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader(
"Access-Control-Allow-Headers",
"Authorization, Content-Type, Accept",
);
response.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS",
);
if (request.method === "OPTIONS") return response.writeHead(204).end();
const url = new URL(request.url, "http://127.0.0.1");
let body;
try {
const chunks = [];
for await (const chunk of request) chunks.push(chunk);
const raw = Buffer.concat(chunks).toString();
body = raw ? JSON.parse(raw) : undefined;
} catch {
return reply(response, {}, { msg: "Invalid fixture request body" }, 400);
}
if (url.pathname === "/__control/reset" && request.method === "POST") {
options = body ?? {};
requests = [];
paid = false;
keys = initialKeys
.slice(0, options.sshLastPageSingleRow ? 11 : initialKeys.length)
.map((key) => ({ ...key }));
return reply(response);
}
if (url.pathname === "/__control/options" && request.method === "POST") {
options = { ...options, ...body };
return reply(response);
}
if (url.pathname === "/__control/requests") return reply(response, requests);
const path = url.pathname.replace(/^\/console\/v1/, "");
const record = {
method: request.method,
path,
query: Object.fromEntries(url.searchParams),
body,
authorization: request.headers.authorization ?? null,
referrer: request.headers.referer ?? null,
handled: true,
};
requests.push(record);
if (path === "/common" && request.method === "GET") {
return reply(response, {
website_name: "本地前端验收",
login_phone_password: options.loginMode === "sms-only" ? 0 : 1,
login_email_password: options.loginMode === "sms-only" ? 0 : 1,
login_phone_verify: options.loginMode === "password-only" ? 0 : 1,
first_login_method:
options.loginMode === "password-only" ? "code" : "password",
captcha_client_login: 0,
captcha_client_login_error: 0,
captcha_client_login_error_3_times: 0,
register_phone: 1,
register_email: 1,
plugin_configuration: { mp_weixin_notice: { scan_login: 0 } },
oauth: [],
});
}
if (path === "/login" && request.method === "POST")
return reply(response, { jwt: token });
if (path === "/phone/code" && request.method === "POST")
return reply(response);
if (request.headers.authorization !== `Bearer ${token}`) {
record.invalidAuthorization = true;
return reply(response, {}, { msg: "Missing fixture session" }, 401);
}
if (path === "/index" && request.method === "GET" && options.expiredLegacy)
return reply(
response,
{},
{ status: 401, msg: "Expired legacy fixture session" },
);
if (path === "/index" && request.method === "GET")
return reply(response, { account });
if (path === "/account" && request.method === "GET")
return reply(response, { account });
if (path === "/menu" && request.method === "GET") {
return reply(response, {
menu: options.emptyMenu
? []
: [
{
id: 1,
name: "SSH 密钥",
menu_type: "custom",
url: "/security/ssh-keys",
},
{ id: 2, name: "订单", menu_type: "custom", url: "/orders" },
],
});
}
if (path === "/client_care/mail" && request.method === "GET") {
return reply(response, { credit_limit: { count: 0, list: [], type: [] } });
}
if (path === "/logout" && request.method === "POST") {
if (options.hangLogout) return;
return reply(response);
}
if (path === "/ssh_key" && request.method === "GET") {
if (options.hangSshBody) {
response.writeHead(200, { "Content-Type": "application/json" });
response.write('{"status":200,"msg":"","data":');
return;
}
if (options.expiredSession)
return reply(
response,
{},
{ status: 401, msg: "Expired fixture session" },
);
const page = Math.max(1, Number(url.searchParams.get("page")) || 1);
const limit = Math.max(1, Number(url.searchParams.get("limit")) || 10);
return reply(response, {
list: keys.slice((page - 1) * limit, page * limit),
count: keys.length,
});
}
if (path === "/ssh_key" && request.method === "POST") {
const id = Math.max(0, ...keys.map((key) => key.id)) + 1;
keys.push({ id, ...body, finger_print: `SHA256:fixture-${id}` });
return reply(response, { id });
}
const keyId = /^\/ssh_key\/(\d+)$/.exec(path);
if (keyId && request.method === "PUT") {
const key = keys.find((entry) => entry.id === Number(keyId[1]));
if (!key) return reply(response, {}, { msg: "Fixture key not found" }, 404);
Object.assign(key, body);
return reply(response);
}
if (keyId && request.method === "DELETE") {
keys = keys.filter((entry) => entry.id !== Number(keyId[1]));
return reply(response);
}
if (path === "/order/42" && request.method === "GET") {
if (options.expiredPayment)
return reply(
response,
{},
{ status: 401, msg: "Expired payment fixture session" },
);
return reply(response, {
order: {
id: 42,
amount: "20.00",
credit: "0.00",
amount_unpaid: paid ? "0.00" : "20.00",
type: "new",
status: paid ? "Paid" : "Unpaid",
create_time: 1700000000,
pay_time: paid ? 1700000060 : 0,
gateway: "alipay",
items: [
{
id: 1,
product_name: "本地测试实例",
description: "前端支付验收",
amount: "20.00",
},
],
},
customfields: { is_pre_invoice: 0 },
});
}
if (path === "/order/42/transaction_record" && request.method === "GET") {
return reply(response, {
list: paid
? [{ amount: "20.00", create_time: 1700000060, description: "alipay" }]
: [],
});
}
if (path === "/gateway" && request.method === "GET") {
return reply(response, {
list: [{ id: 1, name: "alipay", title: "本地测试支付" }],
});
}
if (path === "/voucher/pay" && request.method === "GET")
return reply(response, { list: [] });
if (path === "/pay" && request.method === "POST") {
if (options.hangPaymentStatus)
return reply(response, { html: '<div role="status">本地支付渠道</div>' });
paid = true;
return reply(response, {}, { code: "Paid" });
}
if (path === "/pay/42/status" && request.method === "GET") {
if (options.hangPaymentStatus) return;
return reply(response, {}, { code: paid ? "Paid" : "Unpaid" });
}
if (path === "/certification/info" && request.method === "GET") {
return reply(response, {
certification_open: 0,
certification_company_open: 0,
is_certification: 0,
});
}
if (
["/ticket", "/announcement", "/host"].includes(path) &&
request.method === "GET"
) {
return reply(response, {
list: [],
count: 0,
...(path === "/host" ? { server_page: "classified-v1" } : {}),
});
}
if (path === "/withdraw/rule/credit" && request.method === "GET")
return reply(response, {});
if (path === "/recommend/promoter" && request.method === "GET")
return reply(response, { promoter: { permission: 0 } });
record.handled = false;
reply(
response,
{},
{ msg: `Unhandled fixture endpoint: ${record.method} ${path}` },
404,
);
});
server.listen(0, "127.0.0.1", () => {
process.stdout.write(
`${JSON.stringify({ origin: `http://127.0.0.1:${server.address().port}` })}\n`,
);
});
process.on("SIGTERM", () => {
server.closeAllConnections();
server.close(() => process.exit(0));
});