"use strict"; const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); const DATA_FILE = path.join(__dirname, "..", "data.json"); const UPLOADS_DIR = path.join(__dirname, "..", "uploads"); const DEFAULT_DEADLINE = "2026-10-15"; const START_COMPANIES = [ "АО «НК «КазМунайГаз»", "АО «НК «КТЖ»", "АО «Казахтелеком»", "АО «KEGOC»", "АО «НАК «Казатомпром»", "АО «Казпочта»", "АО «Самрук-Энерго»", "ТОО «Самрук-Казына Инвест»", "ТОО «Самрук-Казына Контракт»", "ТОО «Samruk-Kazyna Ondeu»", "АО «НГК «Таукен Самрук»", "АО «Samruk-Kazyna Construction»", "АО «НК «QazaqGaz»", "ТОО «ПГУ Туркестан»", "АО «ФНБ «Самрук-Казына»", ]; function ensureUploadsDir() { if (!fs.existsSync(UPLOADS_DIR)) fs.mkdirSync(UPLOADS_DIR, { recursive: true }); } function readRaw() { if (!fs.existsSync(DATA_FILE)) return null; try { return JSON.parse(fs.readFileSync(DATA_FILE, "utf8")); } catch (e) { return null; } } function writeRaw(db) { fs.writeFileSync(DATA_FILE, JSON.stringify(db, null, 2)); } function randPassword(len) { const abc = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789"; let s = ""; const buf = crypto.randomBytes(len); for (let i = 0; i < len; i++) s += abc[buf[i] % abc.length]; return s; } function makeUser(record) { const salt = crypto.randomBytes(32); const pw = randPassword(12); const hash = crypto.scryptSync(pw, salt, 32); return Object.assign( { failedCount: 0, lockedUntil: 0 }, record, { salt: salt.toString("hex"), passwordHash: hash.toString("hex"), active: true, } ); } function seed() { ensureUploadsDir(); const db = { period: "3-й квартал 2026", deadline: DEFAULT_DEADLINE, consolidatorPhone: "", users: [], reports: [], }; const consPw = randPassword(12); const cons = makeUser({ id: "u_consolidator", role: "consolidator", name: "", companyName: "", login: "svod", }); db._consolidatorTempPassword = consPw; db.users.push(cons); START_COMPANIES.forEach(function (name, i) { const u = makeUser({ id: "u_" + i, role: "subsidiary", name: "", companyName: name, person: "", phone: "", login: "c" + (i + 1), }); db.users.push(u); }); writeRaw(db); return db; } function load() { let db = readRaw(); if (!db || !Array.isArray(db.users) || !Array.isArray(db.reports)) { db = seed(); } if (!Array.isArray(db.reports)) db.reports = []; if (!db.period) db.period = "3-й квартал 2026"; if (!db.deadline) db.deadline = DEFAULT_DEADLINE; db.users.forEach(function (u) { if (typeof u.failedCount !== "number") u.failedCount = 0; if (typeof u.lockedUntil !== "number") u.lockedUntil = 0; if (typeof u.active !== "boolean") u.active = true; }); return db; } function save(db) { writeRaw(db); } function genId(prefix) { return prefix + "_" + Date.now().toString(36) + "_" + crypto.randomBytes(4).toString("hex"); } function hashPassword(password, saltHex) { const salt = Buffer.from(saltHex, "hex"); return crypto.scryptSync(password, salt, 32).toString("hex"); } function verifyPassword(password, saltHex, expectedHex) { const hash = Buffer.from(hashPassword(password, saltHex), "hex"); const expected = Buffer.from(expectedHex, "hex"); return hash.length === expected.length && crypto.timingSafeEqual(hash, expected); } module.exports = { DATA_FILE: DATA_FILE, UPLOADS_DIR: UPLOADS_DIR, ensureUploadsDir: ensureUploadsDir, randPassword: randPassword, makeUser: makeUser, load: load, save: save, genId: genId, START_COMPANIES: START_COMPANIES, verifyPassword: verifyPassword, };