fix(POSTV1-02): 修复便携版网页入口门禁
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
This commit is contained in:
+12
-3
@@ -238,6 +238,7 @@ export interface CreateAppOptions {
|
|||||||
assetReleases?: AssetReleaseReader;
|
assetReleases?: AssetReleaseReader;
|
||||||
bootstrap?: () => BootstrapResponse | Promise<BootstrapResponse>;
|
bootstrap?: () => BootstrapResponse | Promise<BootstrapResponse>;
|
||||||
browserGate?: boolean;
|
browserGate?: boolean;
|
||||||
|
productIndexHtml?: string;
|
||||||
browserSupportRelease?: BrowserSupportRelease;
|
browserSupportRelease?: BrowserSupportRelease;
|
||||||
browserSupportSecret?: Buffer;
|
browserSupportSecret?: Buffer;
|
||||||
credits?: CreditService;
|
credits?: CreditService;
|
||||||
@@ -273,7 +274,7 @@ const supportGateHtml = readFileSync(resolve(supportGateDirectory, "index.html")
|
|||||||
const supportGateCss = readFileSync(resolve(supportGateDirectory, "support-gate.css"), "utf8");
|
const supportGateCss = readFileSync(resolve(supportGateDirectory, "support-gate.css"), "utf8");
|
||||||
const supportGateJavaScript = readFileSync(resolve(supportGateDirectory, "support-gate.js"), "utf8");
|
const supportGateJavaScript = readFileSync(resolve(supportGateDirectory, "support-gate.js"), "utf8");
|
||||||
const productWebRoot = resolve(process.env.DADA_WEB_ROOT ?? "apps/web/dist");
|
const productWebRoot = resolve(process.env.DADA_WEB_ROOT ?? "apps/web/dist");
|
||||||
const productIndexHtml = existsSync(resolve(productWebRoot, "index.html"))
|
const packagedProductIndexHtml = existsSync(resolve(productWebRoot, "index.html"))
|
||||||
? readFileSync(resolve(productWebRoot, "index.html"), "utf8")
|
? readFileSync(resolve(productWebRoot, "index.html"), "utf8")
|
||||||
: undefined;
|
: undefined;
|
||||||
const clientHints = "Sec-CH-UA, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform";
|
const clientHints = "Sec-CH-UA, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform";
|
||||||
@@ -714,6 +715,7 @@ export async function createApp(options: CreateAppOptions = {}) {
|
|||||||
)
|
)
|
||||||
: undefined);
|
: undefined);
|
||||||
const browserGate = options.browserGate ?? true;
|
const browserGate = options.browserGate ?? true;
|
||||||
|
const productIndexHtml = options.productIndexHtml ?? packagedProductIndexHtml;
|
||||||
const browserSupportSecret = options.browserSupportSecret ?? randomBytes(32);
|
const browserSupportSecret = options.browserSupportSecret ?? randomBytes(32);
|
||||||
const browserSupportRelease = options.browserSupportRelease;
|
const browserSupportRelease = options.browserSupportRelease;
|
||||||
const app = Fastify({
|
const app = Fastify({
|
||||||
@@ -905,9 +907,16 @@ export async function createApp(options: CreateAppOptions = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const route of ["/", "/app", "/app/*", "/admin", "/admin/*"]) {
|
for (const route of ["/", "/app", "/app/*", "/admin", "/admin/*"]) {
|
||||||
app.get(route, { schema: { hide: true } }, async (_request, reply) => {
|
app.get(route, { schema: { hide: true } }, async (request, reply) => {
|
||||||
reply.type("text/html; charset=utf-8");
|
reply.type("text/html; charset=utf-8");
|
||||||
return productIndexHtml ?? supportGateHtml;
|
if (!browserGate) return productIndexHtml ?? supportGateHtml;
|
||||||
|
const verified = verifyBrowserSupportCookie({
|
||||||
|
cookieHeader: headerValue(request.headers.cookie),
|
||||||
|
release: browserSupportRelease,
|
||||||
|
secChUa: headerValue(request.headers["sec-ch-ua"]),
|
||||||
|
secret: browserSupportSecret,
|
||||||
|
});
|
||||||
|
return verified.supported && productIndexHtml ? productIndexHtml : supportGateHtml;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
app.get("/assets/*", { schema: { hide: true } }, async (request, reply) => {
|
app.get("/assets/*", { schema: { hide: true } }, async (request, reply) => {
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ async function checkSupport() {
|
|||||||
browserValue.textContent = `${result.browser.brand} ${result.browser.major}`;
|
browserValue.textContent = `${result.browser.brand} ${result.browser.major}`;
|
||||||
supportedValue.textContent = supportedLabel(result.supported_browsers);
|
supportedValue.textContent = supportedLabel(result.supported_browsers);
|
||||||
window.dispatchEvent(new CustomEvent("dada:support-ready"));
|
window.dispatchEvent(new CustomEvent("dada:support-ready"));
|
||||||
|
window.location.replace(window.location.pathname.startsWith("/admin") ? "/admin" : "/app");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showBlocked(
|
showBlocked(
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
import { resolve } from "node:path";
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
import { buildAndValidatePortablePackage } from "./lib/portable-package.mjs";
|
import { buildAndValidatePortablePackage } from "./lib/portable-package.mjs";
|
||||||
|
import { validateFinalReleaseRecord } from "./lib/wp7-07-final-release.mjs";
|
||||||
|
|
||||||
const outputIndex = process.argv.indexOf("--output");
|
const outputIndex = process.argv.indexOf("--output");
|
||||||
const outputRoot = outputIndex >= 0 ? resolve(process.argv[outputIndex + 1]) : resolve(".build", "portable-release");
|
const outputRoot = outputIndex >= 0 ? resolve(process.argv[outputIndex + 1]) : resolve(".build", "portable-release");
|
||||||
const result = await buildAndValidatePortablePackage({ outputRoot });
|
const previousRelease = JSON.parse(readFileSync(resolve("RELEASE.json"), "utf8"));
|
||||||
|
const releaseRecord = validateFinalReleaseRecord({
|
||||||
|
...previousRelease,
|
||||||
|
buildCommit: execFileSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }).trim(),
|
||||||
|
maintenanceFromCommit: previousRelease.buildCommit,
|
||||||
|
recordedAt: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
const result = await buildAndValidatePortablePackage({ outputRoot, releaseRecord });
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
package: result.packageManifest.package_name,
|
package: result.packageManifest.package_name,
|
||||||
sha256: result.packageManifest.zip_sha256,
|
sha256: result.packageManifest.zip_sha256,
|
||||||
|
|||||||
@@ -125,7 +125,12 @@ afterAll(async () => {
|
|||||||
|
|
||||||
describe("TDD-WP0-BRW-001 supported browser contract", () => {
|
describe("TDD-WP0-BRW-001 supported browser contract", () => {
|
||||||
it("cross-checks UA-CH and issues only a short-lived signed support cookie", async () => {
|
it("cross-checks UA-CH and issues only a short-lived signed support cookie", async () => {
|
||||||
const app = await createApp({ browserSupportRelease: testBrowserSupportRelease } as never);
|
const app = await createApp({
|
||||||
|
browserSupportRelease: testBrowserSupportRelease,
|
||||||
|
productIndexHtml: "<!doctype html><title>Dada product test</title><div id=\"root\"></div>",
|
||||||
|
} as never);
|
||||||
|
const gate = await app.inject({ headers: { host: "127.0.0.1:43121" }, method: "GET", url: "/" });
|
||||||
|
expect(gate.body).toContain("当前浏览器无法使用 Dada");
|
||||||
const checked = await app.inject({
|
const checked = await app.inject({
|
||||||
headers: supportedEdge.headers,
|
headers: supportedEdge.headers,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -150,6 +155,14 @@ describe("TDD-WP0-BRW-001 supported browser contract", () => {
|
|||||||
|
|
||||||
const cookie = supportCookie(checked);
|
const cookie = supportCookie(checked);
|
||||||
expect(cookie).toBeDefined();
|
expect(cookie).toBeDefined();
|
||||||
|
const productHtml = await app.inject({
|
||||||
|
headers: { cookie, host: "127.0.0.1:43121", "sec-ch-ua": supportedEdge.headers["sec-ch-ua"] },
|
||||||
|
method: "GET",
|
||||||
|
url: "/app",
|
||||||
|
});
|
||||||
|
expect(productHtml.statusCode).toBe(200);
|
||||||
|
expect(productHtml.body).toContain("Dada product test");
|
||||||
|
expect(productHtml.body).not.toContain("当前浏览器无法使用 Dada");
|
||||||
const product = await app.inject({
|
const product = await app.inject({
|
||||||
headers: {
|
headers: {
|
||||||
cookie,
|
cookie,
|
||||||
|
|||||||
@@ -125,18 +125,20 @@ test("portable package serves the product and keeps SQLite data across API resta
|
|||||||
let api = startApi(configPath, dataRoot);
|
let api = startApi(configPath, dataRoot);
|
||||||
try {
|
try {
|
||||||
await waitForHealth(api);
|
await waitForHealth(api);
|
||||||
|
const initialPage = await fetch(`http://127.0.0.1:${port}/`, { headers: { host: `127.0.0.1:${port}` } });
|
||||||
|
assert.equal(initialPage.status, 200);
|
||||||
|
assert.match(await initialPage.text(), /当前浏览器无法使用 Dada/);
|
||||||
const support = await fetch(`http://127.0.0.1:${port}/api/v1/support/check`, {
|
const support = await fetch(`http://127.0.0.1:${port}/api/v1/support/check`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { host: `127.0.0.1:${port}`, origin: `http://127.0.0.1:${port}`, "content-type": "application/json", "sec-ch-ua": '"Google Chrome";v="150"', "sec-ch-ua-full-version-list": '"Google Chrome";v="150.0.0.0"', "sec-ch-ua-platform": '"Windows"' },
|
headers: { host: `127.0.0.1:${port}`, origin: `http://127.0.0.1:${port}`, "content-type": "application/json", "sec-ch-ua": '"Google Chrome";v="150"', "sec-ch-ua-full-version-list": '"Google Chrome";v="150.0.0.0"', "sec-ch-ua-platform": '"Windows"' },
|
||||||
body: JSON.stringify({ brands: [{ brand: "Google Chrome", version: "150" }], full_version_list: [{ brand: "Google Chrome", version: "150.0.0.0" }], platform: "Windows" }),
|
body: JSON.stringify({ brands: [{ brand: "Google Chrome", version: "150" }], full_version_list: [{ brand: "Google Chrome", version: "150.0.0.0" }], platform: "Windows" }),
|
||||||
});
|
});
|
||||||
assert.ok([200, 426].includes(support.status));
|
assert.equal(support.status, 200);
|
||||||
if (support.status === 200) {
|
|
||||||
const cookie = support.headers.get("set-cookie")?.split(";", 1)[0];
|
const cookie = support.headers.get("set-cookie")?.split(";", 1)[0];
|
||||||
const page = await fetch(`http://127.0.0.1:${port}/app`, { headers: { host: `127.0.0.1:${port}`, cookie } });
|
assert.ok(cookie);
|
||||||
|
const page = await fetch(`http://127.0.0.1:${port}/app`, { headers: { host: `127.0.0.1:${port}`, cookie, "sec-ch-ua": '"Google Chrome";v="150"' } });
|
||||||
assert.equal(page.status, 200);
|
assert.equal(page.status, 200);
|
||||||
assert.match(await page.text(), /<div id="root"><\/div>/);
|
assert.match(await page.text(), /<div id="root"><\/div>/);
|
||||||
}
|
|
||||||
assert.ok(existsSync(join(dataRoot, "db", "dada.sqlite3")));
|
assert.ok(existsSync(join(dataRoot, "db", "dada.sqlite3")));
|
||||||
await verifyWorkerStartup(configPath);
|
await verifyWorkerStartup(configPath);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user