Update data generator and researcher maps
Browse files- generate-data.mjs +45 -15
generate-data.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
|
|
| 2 |
import crypto from "node:crypto";
|
| 3 |
import { FileBlob, SpreadsheetFile } from "@oai/artifact-tool";
|
| 4 |
|
| 5 |
-
const [inputPath, outputPath, password = "20302030"] = process.argv.slice(2);
|
| 6 |
|
| 7 |
const MAP_URLS = [
|
| 8 |
["أماني مصطفى عبدالله الطيب", "https://stat2025-map.static.hf.space/Rahn/01.html"],
|
|
@@ -89,6 +89,41 @@ function mapUrlFor(researcher) {
|
|
| 89 |
return partial?.[1] || "";
|
| 90 |
}
|
| 91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
if (!inputPath || !outputPath) {
|
| 93 |
console.error("Usage: node generate-data.mjs <input.xlsx> <output.js> [password]");
|
| 94 |
process.exitCode = 1;
|
|
@@ -119,7 +154,7 @@ if (!inputPath || !outputPath) {
|
|
| 119 |
? "statement"
|
| 120 |
: "none";
|
| 121 |
|
| 122 |
-
|
| 123 |
researcher,
|
| 124 |
establishmentName,
|
| 125 |
contractNumber: clean(source[3]),
|
|
@@ -135,7 +170,9 @@ if (!inputPath || !outputPath) {
|
|
| 135 |
unifiedNumber: clean(source[12]),
|
| 136 |
activityCode: clean(source[13]),
|
| 137 |
activity: clean(source[14]),
|
| 138 |
-
}
|
|
|
|
|
|
|
| 139 |
}
|
| 140 |
|
| 141 |
const counts = new Map();
|
|
@@ -155,20 +192,13 @@ if (!inputPath || !outputPath) {
|
|
| 155 |
});
|
| 156 |
|
| 157 |
const iterations = 310000;
|
| 158 |
-
const
|
| 159 |
-
const
|
| 160 |
-
const key = crypto.pbkdf2Sync(password, salt, iterations, 32, "sha256");
|
| 161 |
-
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
| 162 |
-
const encrypted = Buffer.concat([cipher.update(plainPayload, "utf8"), cipher.final()]);
|
| 163 |
-
const combined = Buffer.concat([encrypted, cipher.getAuthTag()]);
|
| 164 |
const output = [
|
| 165 |
"/* Generated encrypted data. Rebuild this file from the source workbook. */",
|
| 166 |
-
"
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
` iv: "${iv.toString("base64")}",`,
|
| 170 |
-
` payload: "${combined.toString("base64")}",`,
|
| 171 |
-
"});",
|
| 172 |
"",
|
| 173 |
].join("\n");
|
| 174 |
|
|
|
|
| 2 |
import crypto from "node:crypto";
|
| 3 |
import { FileBlob, SpreadsheetFile } from "@oai/artifact-tool";
|
| 4 |
|
| 5 |
+
const [inputPath, outputPath, password = "20302030", supervisorPassword = "1448"] = process.argv.slice(2);
|
| 6 |
|
| 7 |
const MAP_URLS = [
|
| 8 |
["أماني مصطفى عبدالله الطيب", "https://stat2025-map.static.hf.space/Rahn/01.html"],
|
|
|
|
| 89 |
return partial?.[1] || "";
|
| 90 |
}
|
| 91 |
|
| 92 |
+
function sampleKey(row) {
|
| 93 |
+
const parts = [
|
| 94 |
+
row.commercialRecord,
|
| 95 |
+
row.contractNumber,
|
| 96 |
+
row.establishmentName,
|
| 97 |
+
row.researcher,
|
| 98 |
+
].map(normalize);
|
| 99 |
+
return crypto.createHash("sha256").update(parts.join("|")).digest("hex").slice(0, 24);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
function encryptPayload(plainPayload, secret, iterations) {
|
| 103 |
+
const salt = crypto.randomBytes(16);
|
| 104 |
+
const iv = crypto.randomBytes(12);
|
| 105 |
+
const key = crypto.pbkdf2Sync(secret, salt, iterations, 32, "sha256");
|
| 106 |
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
| 107 |
+
const encrypted = Buffer.concat([cipher.update(plainPayload, "utf8"), cipher.final()]);
|
| 108 |
+
return {
|
| 109 |
+
iterations,
|
| 110 |
+
salt: salt.toString("base64"),
|
| 111 |
+
iv: iv.toString("base64"),
|
| 112 |
+
payload: Buffer.concat([encrypted, cipher.getAuthTag()]).toString("base64"),
|
| 113 |
+
};
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
function encryptedBlock(name, encrypted) {
|
| 117 |
+
return [
|
| 118 |
+
`const ${name} = Object.freeze({`,
|
| 119 |
+
` iterations: ${encrypted.iterations},`,
|
| 120 |
+
` salt: "${encrypted.salt}",`,
|
| 121 |
+
` iv: "${encrypted.iv}",`,
|
| 122 |
+
` payload: "${encrypted.payload}",`,
|
| 123 |
+
"});",
|
| 124 |
+
].join("\n");
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
if (!inputPath || !outputPath) {
|
| 128 |
console.error("Usage: node generate-data.mjs <input.xlsx> <output.js> [password]");
|
| 129 |
process.exitCode = 1;
|
|
|
|
| 154 |
? "statement"
|
| 155 |
: "none";
|
| 156 |
|
| 157 |
+
const row = {
|
| 158 |
researcher,
|
| 159 |
establishmentName,
|
| 160 |
contractNumber: clean(source[3]),
|
|
|
|
| 170 |
unifiedNumber: clean(source[12]),
|
| 171 |
activityCode: clean(source[13]),
|
| 172 |
activity: clean(source[14]),
|
| 173 |
+
};
|
| 174 |
+
row.sampleKey = sampleKey(row);
|
| 175 |
+
rows.push(row);
|
| 176 |
}
|
| 177 |
|
| 178 |
const counts = new Map();
|
|
|
|
| 192 |
});
|
| 193 |
|
| 194 |
const iterations = 310000;
|
| 195 |
+
const researcherEncrypted = encryptPayload(plainPayload, password, iterations);
|
| 196 |
+
const supervisorEncrypted = encryptPayload(plainPayload, supervisorPassword, iterations);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
const output = [
|
| 198 |
"/* Generated encrypted data. Rebuild this file from the source workbook. */",
|
| 199 |
+
encryptedBlock("ENCRYPTED_DATA", researcherEncrypted),
|
| 200 |
+
"",
|
| 201 |
+
encryptedBlock("SUPERVISOR_ENCRYPTED_DATA", supervisorEncrypted),
|
|
|
|
|
|
|
|
|
|
| 202 |
"",
|
| 203 |
].join("\n");
|
| 204 |
|