import fs from "node:fs/promises"; import crypto from "node:crypto"; import { FileBlob, SpreadsheetFile } from "@oai/artifact-tool"; const [inputPath, outputPath, password] = process.argv.slice(2); if (!inputPath || !outputPath || !password) { console.error("Usage: node generate-data.mjs "); process.exitCode = 1; } else { const blob = await FileBlob.load(inputPath); const workbook = await SpreadsheetFile.importXlsx(blob); const sheet = workbook.worksheets.getItemAt(0); const values = sheet.getUsedRange(true).values; const headers = values[0].map((value) => String(value ?? "").trim()); const rows = values.slice(1).map((row) => headers.map((_, index) => { const value = row[index]; if (value === null || value === undefined) return ""; return typeof value === "string" ? value.trim() : String(value); }), ); const payload = JSON.stringify({ version: 1, generatedAt: new Date().toISOString(), headers, rows, }); const iterations = 310000; const salt = crypto.randomBytes(16); const iv = crypto.randomBytes(12); const key = crypto.pbkdf2Sync(password, salt, iterations, 32, "sha256"); const cipher = crypto.createCipheriv("aes-256-gcm", key, iv); const encrypted = Buffer.concat([cipher.update(payload, "utf8"), cipher.final()]); const authTag = cipher.getAuthTag(); const combined = Buffer.concat([encrypted, authTag]); const output = [ "/* Generated encrypted data. Replace this file using generate-data.mjs when the workbook changes. */", "const ENCRYPTED_DATA = Object.freeze({", ` iterations: ${iterations},`, ` salt: "${salt.toString("base64")}",`, ` iv: "${iv.toString("base64")}",`, ` payload: "${combined.toString("base64")}",`, "});", "", ].join("\n"); await fs.writeFile(outputPath, output, "utf8"); console.log( JSON.stringify({ rows: rows.length, columns: headers.length, encryptedBytes: combined.length, outputPath, }), ); }