Inject a Tauri shell script during CI prep to disable service workers and attach Bearer tokens on cross-origin API requests. Enable Android third-party cookies in MainActivity and eval the same script from Rust on page load.
124 lines
3.8 KiB
JavaScript
124 lines
3.8 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import AdmZip from "adm-zip";
|
|
import { BUNDLE_ICONS, generateAppIcons } from "./generate-app-icons.mjs";
|
|
import { injectInAppNav } from "./inject-in-app-nav.mjs";
|
|
import { injectTauriShell } from "./inject-tauri-shell.mjs";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.resolve(__dirname, "../..");
|
|
|
|
const jobId = process.env.JOB_ID;
|
|
const appNameZh = process.env.APP_NAME;
|
|
const appNameEn = process.env.APP_NAME_EN;
|
|
const appIdentifier = process.env.APP_IDENTIFIER;
|
|
|
|
if (!jobId || !appNameZh || !appNameEn || !appIdentifier) {
|
|
console.error(
|
|
"JOB_ID, APP_NAME, APP_NAME_EN, and APP_IDENTIFIER are required",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
function readAppVersion(jobId) {
|
|
const versionFile = path.join(root, "builds", jobId, "version.txt");
|
|
if (fs.existsSync(versionFile)) {
|
|
const fromFile = fs.readFileSync(versionFile, "utf8").trim();
|
|
if (fromFile) return fromFile;
|
|
}
|
|
const fromEnv = (process.env.APP_VERSION ?? "").trim();
|
|
return fromEnv || "1.0.0";
|
|
}
|
|
|
|
const appVersion = readAppVersion(jobId);
|
|
const zipPath = path.join(root, "builds", jobId, "site.zip");
|
|
const distDir = path.join(root, "template", "dist");
|
|
const confPath = path.join(root, "template", "src-tauri", "tauri.conf.json");
|
|
const androidConfPath = path.join(
|
|
root,
|
|
"template",
|
|
"src-tauri",
|
|
"tauri.android.conf.json",
|
|
);
|
|
|
|
if (!fs.existsSync(zipPath)) {
|
|
console.error(`Missing upload: ${zipPath}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
fs.rmSync(distDir, { recursive: true, force: true });
|
|
fs.mkdirSync(distDir, { recursive: true });
|
|
|
|
const zip = new AdmZip(zipPath);
|
|
zip.extractAllTo(distDir, true);
|
|
|
|
const indexPath = path.join(distDir, "index.html");
|
|
if (!fs.existsSync(indexPath)) {
|
|
console.error("template/dist/index.html not found after extraction");
|
|
process.exit(1);
|
|
}
|
|
|
|
const buildDir = path.join(root, "builds", jobId);
|
|
for (const iconName of ["logo.png", "logo.jpg", "logo.jpeg", "favicon.ico"]) {
|
|
const iconSrc = path.join(buildDir, iconName);
|
|
if (fs.existsSync(iconSrc)) {
|
|
fs.copyFileSync(iconSrc, path.join(distDir, iconName));
|
|
console.log(`Copied uploaded icon: builds/${jobId}/${iconName}`);
|
|
}
|
|
}
|
|
|
|
function toSafeBinaryName(name, fallback) {
|
|
const ascii = name.replace(/[^a-zA-Z0-9_-]+/g, "");
|
|
return (ascii || fallback).slice(0, 64);
|
|
}
|
|
|
|
function patchTauriConfig(filePath) {
|
|
const conf = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
const safeBinaryName = toSafeBinaryName(appNameEn, `App${jobId}`);
|
|
conf.productName = appNameZh;
|
|
if (filePath === confPath) {
|
|
conf.mainBinaryName = safeBinaryName;
|
|
}
|
|
conf.identifier = appIdentifier;
|
|
conf.version = appVersion;
|
|
if (conf.app?.windows?.[0]) {
|
|
conf.app.windows[0].title = appNameZh;
|
|
}
|
|
conf.app = {
|
|
...conf.app,
|
|
security: {
|
|
csp: {
|
|
"default-src": "'self' asset: tauri: https: http: data: blob: file:",
|
|
"connect-src":
|
|
"'self' asset: tauri: https: http: ws: wss: data: blob: file:",
|
|
"img-src": "'self' asset: tauri: https: http: data: blob: file:",
|
|
"media-src": "'self' asset: tauri: https: http: data: blob: file:",
|
|
"style-src": "'self' 'unsafe-inline' asset: tauri: https: http:",
|
|
"script-src":
|
|
"'self' 'unsafe-inline' 'unsafe-eval' asset: tauri: https: http:",
|
|
"frame-src": "'self' asset: tauri: https: http: data: blob:",
|
|
"worker-src": "'self' blob: data:",
|
|
},
|
|
},
|
|
};
|
|
conf.bundle = {
|
|
...conf.bundle,
|
|
active: true,
|
|
icon: BUNDLE_ICONS,
|
|
};
|
|
fs.writeFileSync(filePath, `${JSON.stringify(conf, null, 2)}\n`);
|
|
}
|
|
|
|
injectTauriShell(distDir);
|
|
injectInAppNav(distDir);
|
|
|
|
patchTauriConfig(confPath);
|
|
if (fs.existsSync(androidConfPath)) {
|
|
patchTauriConfig(androidConfPath);
|
|
}
|
|
|
|
await generateAppIcons({ jobId });
|
|
|
|
console.log("Template prepared successfully");
|