149 lines
3.7 KiB
JavaScript
149 lines
3.7 KiB
JavaScript
/* eslint-disable no-console */
|
|
|
|
import crypto from "crypto";
|
|
import fs from "fs";
|
|
import http from "http";
|
|
import https from "https";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
import zlib from "zlib";
|
|
|
|
import * as tar from "tar";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const BRANDING_INFO_FILE = path.join(__dirname, "../.branding");
|
|
const BRANDING_DIR = path.join(__dirname, "../branding");
|
|
const INSTALLED_BRANDING_INFO_FILE = path.join(BRANDING_DIR, ".branding");
|
|
const TEMP_FILE = path.join(__dirname, "branding_download.tar.gz");
|
|
|
|
function downloadFile(url, dest) {
|
|
return new Promise((resolve, reject) => {
|
|
const file = fs.createWriteStream(dest);
|
|
const protocol = url.startsWith("https") ? https : http;
|
|
|
|
const request = protocol.get(url, (response) => {
|
|
if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 307) {
|
|
file.close();
|
|
fs.unlink(dest, () => {});
|
|
if (response.headers.location) {
|
|
downloadFile(response.headers.location, dest).then(resolve).catch(reject);
|
|
} else {
|
|
reject(new Error("Redirect location missing"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (response.statusCode !== 200) {
|
|
file.close();
|
|
fs.unlink(dest, () => {});
|
|
reject(new Error(`Failed to download: ${response.statusCode}`));
|
|
return;
|
|
}
|
|
|
|
response.pipe(file);
|
|
file.on("finish", () => {
|
|
file.close(resolve);
|
|
});
|
|
});
|
|
|
|
request.on("error", (err) => {
|
|
fs.unlink(dest, () => {});
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
if (!fs.existsSync(BRANDING_INFO_FILE)) {
|
|
console.error(`Branding info file not found at ${BRANDING_INFO_FILE}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const content = fs.readFileSync(BRANDING_INFO_FILE, "utf8");
|
|
|
|
if (fs.existsSync(INSTALLED_BRANDING_INFO_FILE)) {
|
|
const installedContent = fs.readFileSync(INSTALLED_BRANDING_INFO_FILE, "utf8");
|
|
if (content === installedContent) {
|
|
console.log("Branding assets are up to date.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
const lines = content
|
|
.split("\n")
|
|
.map((l) => l.trim())
|
|
.filter((l) => l.length > 0);
|
|
|
|
if (lines.length < 2) {
|
|
console.error("Branding file must contain at least two lines: URL and Hash");
|
|
process.exit(1);
|
|
}
|
|
|
|
const url = lines[0];
|
|
const expectedHash = lines[1];
|
|
|
|
console.log(`Downloading branding assets from <${url}>...`);
|
|
|
|
try {
|
|
await downloadFile(url, TEMP_FILE);
|
|
} catch (err) {
|
|
console.error("Download failed:", err);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("Download complete. Verifying hash...");
|
|
|
|
const fileBuffer = fs.readFileSync(TEMP_FILE);
|
|
const hashSum = crypto.createHash("sha256");
|
|
hashSum.update(fileBuffer);
|
|
const hex = hashSum.digest("hex");
|
|
|
|
if (hex !== expectedHash) {
|
|
console.error("Hash mismatch!");
|
|
console.error(`Expected: ${expectedHash}`);
|
|
console.error(`Actual: ${hex}`);
|
|
if (fs.existsSync(TEMP_FILE)) fs.unlinkSync(TEMP_FILE);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("Hash verified. Extracting...");
|
|
|
|
if (fs.existsSync(BRANDING_DIR)) {
|
|
fs.rmSync(BRANDING_DIR, { recursive: true, force: true });
|
|
}
|
|
fs.mkdirSync(BRANDING_DIR, { recursive: true });
|
|
|
|
try {
|
|
// Extract the tar.gz file
|
|
await new Promise((resolve, reject) => {
|
|
fs.createReadStream(TEMP_FILE)
|
|
.pipe(zlib.createGunzip())
|
|
.pipe(
|
|
tar.x({
|
|
cwd: BRANDING_DIR,
|
|
strip: 1,
|
|
}),
|
|
)
|
|
.on("error", reject)
|
|
.on("finish", resolve);
|
|
});
|
|
fs.copyFileSync(BRANDING_INFO_FILE, INSTALLED_BRANDING_INFO_FILE);
|
|
console.log("Extraction complete.");
|
|
} catch (error) {
|
|
console.error("Failed to extract archive:", error);
|
|
} finally {
|
|
if (fs.existsSync(TEMP_FILE)) {
|
|
fs.unlinkSync(TEMP_FILE);
|
|
}
|
|
}
|
|
}
|
|
|
|
main()
|
|
.then(() => process.exit(0))
|
|
.catch((err) => {
|
|
console.error("An error occurred:", err);
|
|
process.exit(1);
|
|
});
|