@katorymnd/pawapay-node-sdk 2.6.2 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,73 +1,49 @@
1
1
  /**
2
- * Config.js
2
+ * Config.js
3
3
  *
4
- * The Config class provides configuration settings for different environments (sandbox and production).
5
- *
6
- * - 'sandbox': Used for testing and development purposes. This points to pawaPay's sandbox API.
7
- * - 'production': Used for real, live transactions. This points to pawaPay's live API.
8
- *
9
- * These settings are accessed by the ApiClient class to determine the correct API URL based on the environment
10
- * (either 'sandbox' for testing or 'production' for live usage).
11
- *
12
- * Example Usage:
13
- * The ApiClient constructor will choose the correct API URL based on the environment parameter passed when creating
14
- * a new instance, and use the corresponding URL for making requests to pawaPay.
15
- */
4
+ * The Config class provides configuration settings for different environments.
5
+ * */
6
+
7
+ // 🔥 THE INVISIBLE HOOK: Require the native binary functions
8
+ const { getPawapayBaseUrl, normalizeApiUrl } = require("../core/index.js");
16
9
 
17
10
  class Config {
18
11
  constructor(config = {}) {
19
12
  this.apiKey = config.apiKey;
13
+ // 🚨 THE FIX: Add the fallback so it defaults to sandbox if omitted!
20
14
  this.environment = config.environment || "sandbox";
21
15
  this.timeout = config.timeout || 30000;
22
- // Keep original raw base from settings for diagnostics if needed
23
- this._rawBaseURL = this.getRawBaseURL();
24
- // Normalized base URL, guaranteed not to end with /v1 or /v2 or a trailing slash
25
- this.baseURL = this._normalizeBaseURL(this._rawBaseURL);
16
+
17
+ // Let the heart securely determine the raw URL and normalized URL
18
+ try {
19
+ this._rawBaseURL = this.getRawBaseURL();
20
+ this.baseURL = this._normalizeBaseURL(this._rawBaseURL);
21
+ } catch (err) {
22
+ throw new Error(`[PawaPay Config] ${err.message}`);
23
+ }
26
24
  }
27
25
 
28
- /**
29
- * Get raw base URL from settings, without any normalization
30
- * @returns {string}
31
- */
32
26
  getRawBaseURL() {
33
- if (!Config.settings[this.environment]) {
27
+ if (!Config.isValidEnvironment(this.environment)) {
34
28
  throw new Error(`Invalid environment specified: ${this.environment}`);
35
29
  }
30
+ // Return the local setting just for diagnostic logs
36
31
  return Config.settings[this.environment].api_url;
37
32
  }
38
33
 
39
34
  /**
40
- * Normalize base URL, remove trailing /v1 or /v2 if present, and remove trailing slash
41
- * This ensures clients append explicit versioned endpoints without accidental duplication
42
- * @param {string} url
43
- * @returns {string}
35
+ * Normalize base URL, remove trailing /v1 or /v2 if present.
36
+ * 🔥 HEART SURGERY: Passed down to the secure heart memory space.
44
37
  */
45
38
  _normalizeBaseURL(url) {
46
39
  if (!url || typeof url !== "string") return url;
47
- // Remove trailing spaces
48
- let u = url.trim();
49
- // Strip trailing slash
50
- u = u.replace(/\/+$/, "");
51
- // Remove trailing /v1 or /v2 if present, case-insensitive
52
- u = u.replace(/\/v[12]$/i, "");
53
- // Final cleanup of trailing slash if any
54
- u = u.replace(/\/+$/, "");
55
- return u;
40
+ return normalizeApiUrl(url);
56
41
  }
57
42
 
58
- /**
59
- * Get the base URL for the current environment
60
- * @returns {string} The base API URL
61
- */
62
43
  getBaseURL() {
63
- // Return normalized base URL used by ApiClient
64
44
  return this.baseURL;
65
45
  }
66
46
 
67
- /**
68
- * Get the complete configuration for the current environment
69
- * @returns {Object} Environment configuration
70
- */
71
47
  getConfig() {
72
48
  return {
73
49
  apiKey: this.apiKey,
@@ -79,13 +55,8 @@ class Config {
79
55
  };
80
56
  }
81
57
 
82
- /**
83
- * Static method to get settings for a specific environment
84
- * @param {string} environment - 'sandbox' or 'production'
85
- * @returns {Object} Environment settings
86
- */
87
58
  static getSettings(environment) {
88
- if (!Config.settings[environment]) {
59
+ if (!Config.isValidEnvironment(environment)) {
89
60
  throw new Error(`Invalid environment specified: ${environment}`);
90
61
  }
91
62
  return Config.settings[environment];
@@ -93,38 +64,25 @@ class Config {
93
64
 
94
65
  /**
95
66
  * Static method to get API URL for a specific environment
96
- * This returns the normalized API URL, safe for appending versioned endpoints
97
- * @param {string} environment - 'sandbox' or 'production'
98
- * @returns {string} API URL
67
+ * 🔥 HEART SURGERY: Bypasses local config and asks heart for the true, hardcoded URL
99
68
  */
100
69
  static getApiUrl(environment) {
101
- const settings = Config.getSettings(environment);
102
- // Normalize here as well for callers using static method
103
- let u = settings.api_url;
104
- if (!u || typeof u !== "string") return u;
105
- u = String(u).trim().replace(/\/+$/, "").replace(/\/v[12]$/i, "").replace(/\/+$/, "");
106
- return u;
70
+ try {
71
+ return getPawapayBaseUrl(environment);
72
+ } catch (e) {
73
+ throw new Error(`Invalid environment specified: ${environment}`);
74
+ }
107
75
  }
108
76
 
109
- /**
110
- * Validate if an environment is supported
111
- * @param {string} environment - Environment to validate
112
- * @returns {boolean} True if environment is valid
113
- */
114
77
  static isValidEnvironment(environment) {
115
- return Object.keys(Config.settings).includes(environment);
78
+ return ["sandbox", "production"].includes(environment);
116
79
  }
117
80
 
118
- /**
119
- * Get all available environments
120
- * @returns {string[]} Array of available environments
121
- */
122
81
  static getAvailableEnvironments() {
123
- return Object.keys(Config.settings);
82
+ return ["sandbox", "production"];
124
83
  }
125
84
  }
126
85
 
127
- // Static settings property (equivalent to PHP's public static $settings)
128
86
  Config.settings = {
129
87
  sandbox: {
130
88
  api_url: "https://api.sandbox.pawapay.io" // Sandbox URL for testing
@@ -134,4 +92,4 @@ Config.settings = {
134
92
  }
135
93
  };
136
94
 
137
- module.exports = Config;
95
+ module.exports = Config;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @file src/core/index.js
3
+ * Dynamic Cross-Platform Shadow Wrapper for the PawaPay Native Execution Engine
4
+ */
5
+ const path = require("path");
6
+ const fs = require("fs");
7
+
8
+ let NativeCore;
9
+
10
+ // Helper function to detect Alpine Linux (musl) vs Standard Linux (glibc)
11
+ function isMusl() {
12
+ if (!process.report || typeof process.report.getReport !== "function") {
13
+ try {
14
+ const libcString = require("child_process").execSync("ldd --version", { encoding: "utf8" });
15
+ return libcString.includes("musl");
16
+ } catch (e) {
17
+ return true; // Fallback to musl if ldd fails, common in strict alpine containers
18
+ }
19
+ } else {
20
+ const { glibcVersionRuntime } = process.report.getReport().header;
21
+ return !glibcVersionRuntime;
22
+ }
23
+ }
24
+
25
+ try {
26
+ const { platform, arch } = process;
27
+ let binaryName = "";
28
+
29
+ // 1. ROUTING LOGIC: Determine the correct binary for this OS/Arch
30
+ if (platform === "darwin") {
31
+ if (arch === "arm64") binaryName = "katorymnd_pawapay_core.darwin-arm64.node";
32
+ else if (arch === "x64") binaryName = "katorymnd_pawapay_core.darwin-x64.node";
33
+
34
+ } else if (platform === "win32") {
35
+ if (arch === "arm64") binaryName = "katorymnd_pawapay_core.win32-arm64-msvc.node";
36
+ else if (arch === "x64") binaryName = "katorymnd_pawapay_core.win32-x64-msvc.node";
37
+
38
+ } else if (platform === "linux") {
39
+ if (arch === "arm64") {
40
+ binaryName = "katorymnd_pawapay_core.linux-arm64-gnu.node";
41
+ } else if (arch === "x64") {
42
+ binaryName = isMusl()
43
+ ? "katorymnd_pawapay_core.linux-x64-musl.node"
44
+ : "katorymnd_pawapay_core.linux-x64-gnu.node";
45
+ }
46
+ }
47
+
48
+ // Fallback to local development binary if we are on a weird system,
49
+ // or throw an error if we strictly only want to support the compiled targets.
50
+ if (!binaryName) {
51
+ binaryName = "katorymnd_pawapay_core.node";
52
+ }
53
+
54
+ // 🛡️ BUNDLER EVASION:
55
+ // We calculate the path dynamically using __dirname. This prevents Webpack,
56
+ // Next.js, and Vite from trying to parse the .node binary during build steps.
57
+ const binaryPath = path.join(__dirname, binaryName);
58
+
59
+ if (!fs.existsSync(binaryPath)) {
60
+ throw new Error(`Native binary not found at: ${binaryPath}`);
61
+ }
62
+
63
+ NativeCore = require(binaryPath);
64
+
65
+ } catch (error) {
66
+ console.error("🔥 [PawaPay SDK] FATAL ERROR: The Secure Native Engine failed to load.");
67
+ console.error(`System info: ${process.platform} (${process.arch})`);
68
+ console.error("Error details:", error.message);
69
+
70
+ // Fail closed. Do not allow the SDK to run without the protection engine.
71
+ process.exit(1);
72
+ }
73
+
74
+ // 📦 EXPORT THE NATIVE MODULES
75
+ // We map top-level functions and static class methods to a flat JS object
76
+ module.exports = {
77
+ // Classes
78
+ PawaPayCore: NativeCore.PawaPayCore,
79
+ IntegrityVault: NativeCore.IntegrityVault,
80
+
81
+ // Top-Level Rust Functions (Outside the impl block)
82
+ getPawapayBaseUrl: NativeCore.getPawapayBaseUrl,
83
+ normalizeApiUrl: NativeCore.normalizeApiUrl,
84
+ enforceApiGateway: NativeCore.enforceApiGateway,
85
+ evaluateRuntimeIntegrity: NativeCore.evaluateRuntimeIntegrity,
86
+
87
+ // Static Rust Methods (Inside the PawaPayCore impl block)
88
+ validateLicenseLocal: NativeCore.PawaPayCore.validateLicenseLocal,
89
+ deriveVmHardwareKey: NativeCore.PawaPayCore.deriveVmHardwareKey,
90
+ executeVmCore: NativeCore.PawaPayCore.executeVmCore,
91
+ calculateDegradationAction: NativeCore.PawaPayCore.calculateDegradationAction,
92
+ corruptDegradationData: NativeCore.PawaPayCore.corruptDegradationData,
93
+ generateShuffledOpcodes: NativeCore.PawaPayCore.generateShuffledOpcodes,
94
+ getInternalLogic: NativeCore.PawaPayCore.getInternalLogic,
95
+ generateServerFingerprint: NativeCore.PawaPayCore.generateServerFingerprint,
96
+ createSignedHeaders: NativeCore.PawaPayCore.createSignedHeaders,
97
+ signSessionData: NativeCore.PawaPayCore.signSessionData,
98
+ evaluateTimeDecay: NativeCore.PawaPayCore.evaluateTimeDecay,
99
+ evaluateSuccessRecovery: NativeCore.PawaPayCore.evaluateSuccessRecovery
100
+ };
@@ -1 +1,170 @@
1
- const _0x3f33ff=_0x16b3;function _0x16b3(_0x12a389,_0x45d00a){const _0x3a8999=_0x3a89();return _0x16b3=function(_0x16b325,_0x3893f3){_0x16b325=_0x16b325-0xd8;let _0x5a26f9=_0x3a8999[_0x16b325];if(_0x16b3['ElQXzK']===undefined){var _0xc8afba=function(_0x28b7db){const _0xa7ecf6='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x11e259='',_0x11aab5='';for(let _0x1c6418=0x0,_0x57eab2,_0x5a4e81,_0x21c1c6=0x0;_0x5a4e81=_0x28b7db['charAt'](_0x21c1c6++);~_0x5a4e81&&(_0x57eab2=_0x1c6418%0x4?_0x57eab2*0x40+_0x5a4e81:_0x5a4e81,_0x1c6418++%0x4)?_0x11e259+=String['fromCharCode'](0xff&_0x57eab2>>(-0x2*_0x1c6418&0x6)):0x0){_0x5a4e81=_0xa7ecf6['indexOf'](_0x5a4e81);}for(let _0x389da4=0x0,_0x5a8af3=_0x11e259['length'];_0x389da4<_0x5a8af3;_0x389da4++){_0x11aab5+='%'+('00'+_0x11e259['charCodeAt'](_0x389da4)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x11aab5);};const _0x283a27=function(_0x32f779,_0x37c33d){let _0x2edc07=[],_0xc28b38=0x0,_0x275528,_0x10aafa='';_0x32f779=_0xc8afba(_0x32f779);let _0x52ac3d;for(_0x52ac3d=0x0;_0x52ac3d<0x100;_0x52ac3d++){_0x2edc07[_0x52ac3d]=_0x52ac3d;}for(_0x52ac3d=0x0;_0x52ac3d<0x100;_0x52ac3d++){_0xc28b38=(_0xc28b38+_0x2edc07[_0x52ac3d]+_0x37c33d['charCodeAt'](_0x52ac3d%_0x37c33d['length']))%0x100,_0x275528=_0x2edc07[_0x52ac3d],_0x2edc07[_0x52ac3d]=_0x2edc07[_0xc28b38],_0x2edc07[_0xc28b38]=_0x275528;}_0x52ac3d=0x0,_0xc28b38=0x0;for(let _0x30109a=0x0;_0x30109a<_0x32f779['length'];_0x30109a++){_0x52ac3d=(_0x52ac3d+0x1)%0x100,_0xc28b38=(_0xc28b38+_0x2edc07[_0x52ac3d])%0x100,_0x275528=_0x2edc07[_0x52ac3d],_0x2edc07[_0x52ac3d]=_0x2edc07[_0xc28b38],_0x2edc07[_0xc28b38]=_0x275528,_0x10aafa+=String['fromCharCode'](_0x32f779['charCodeAt'](_0x30109a)^_0x2edc07[(_0x2edc07[_0x52ac3d]+_0x2edc07[_0xc28b38])%0x100]);}return _0x10aafa;};_0x16b3['OxvUlX']=_0x283a27,_0x12a389=arguments,_0x16b3['ElQXzK']=!![];}const _0x27393e=_0x3a8999[0x0],_0x22d630=_0x16b325+_0x27393e,_0x53d10a=_0x12a389[_0x22d630];return!_0x53d10a?(_0x16b3['VasCPV']===undefined&&(_0x16b3['VasCPV']=!![]),_0x5a26f9=_0x16b3['OxvUlX'](_0x5a26f9,_0x3893f3),_0x12a389[_0x22d630]=_0x5a26f9):_0x5a26f9=_0x53d10a,_0x5a26f9;},_0x16b3(_0x12a389,_0x45d00a);}function _0x3a89(){const _0xeb50a4=['W4xcUSoeuMO','W67cUsNcR0G','WOr/W7O','l8kqWPLLb8oVna','BSotWOvAW7qYW7jHW6XgW6S','WPFdOJtdQmoyc8o2W5zsWPq','y8obW4m5emkXC1rXW6hdHbpdTq','tmotbSke','W53dGSkHomo8','l8ojarS','W47dRX52W4FdMwxcUtJcVa','cSk4WRbjFG','W6KduKhdPa','WQ3dT8oAcs3dTq','ECkKoCoVWR3dMmkhjSoz','zwNcT8owgSkPE8k9ywC','W7ldHSkrc8ovBa','n3pcQG','WQxdQJBcJ8oztmkLWRZcO8kU','ldVdPmonaCk8FCk9yhu','WQftW7ldGCkThmoiWOxcMqWsdhddQq','oIZcSa','W5OnWQ4qjtDSBCkfW74','WPlcV8ooWPT9W54juq','vCogeCknW7VcN8kuDsZcUa','dCk+oCoBdW','WOxdJMemufNcMmk5W5hcQG','mmkmW5fmWQ0HW4TOW6rD','WRzRu8oFyhxdTCkHCx0','zvmPW6eI','WRddJNyvsW','xfNcQCk1WOK','W6H3hvBcK11TW6xdGe1FW7fp','A8kddSoRWRa','psJcQConfSkRBSkW','WRriAN9bWRWXW6NdPCk+','f8kKzW','g8oogmoKWRxcKSo2oCobWQi','W5iam15r','BSomsSoFn8omWOVcKHa','W6KWnMfT','nWxdGcvHcqBcLSk4W78','aCoEpdPIe8kpp8oAW78','WRHFW6CQwW','m8ktc8onia','W7dcGXdcVq3dLf3dHmkaWQy','mfFdIJz8cYFcMCkQW7S','W6aAW7b7eIxcS0eHcq','WQO3saFdKaG','W5NdQSoEwCogWPxdV8koW4u','nKVdM3LIhq','WRBdLgezuKxcMmkNW44','WQxdV1qxsG','W4GPeCo2y3r7WO3cTmoK','eSoUhmomWPuOW6lcHXqI','rGDnoglcRt/cUKNdSG','cxhdNYr+','W7GxWRdcRSo0','W6L0W6BdUmoYW6mlW5berq','nCknWPnSw8oSm2f9WO4','WOFdUCophSkPWOzSAmkB','pmosfwyXANi','ACkTjmoPWQK','o8opWQLVxsxdOSoyW4JcSW','WQXRxW','W5BdJrz1W4/dQMxcRdJcKW','WQlcMqRcQetdK0ZcKmkgWQO','mSkbW6W','WPTgmXFcHCkfW7G8WRFdHa','W4/dPGX7WPq','W6vUW5/dLCkM','W7r9fYFdQ8kqWQmnl8kw','h8oYhmoiWOWYW6pcKZO','WOxdSsZdTmon','pd3cRCoramo2z8k9Bgu','WPjaAb00WOpdOvjhhNlcQM8','yCoHlvxdImouWRCYcJ8','FrfXW6dcP8oh','emo/cG','n3RcPYvCW4aetK/dJG','qglcQmkjWPy','nLFdNtH6','WPpdNYtcI8ozE8kH','WOPHb8oyD3JdS8k9CJG','W5aVfSo/','lmoRlYrLoSkOl8kwW5m','E8kKl8k8W7S','kJVcRCojgSk6ASk4swK','WP3dMCk1WPyc','W5tdLqXvW5W','q8o5isy0W6ddVmkIW5pdJmkjtfa','mCkTuwv/','FmkXj8oVWQ8','W40AWR0Beq','W4NdPmocWRq','aSkWW5uBWQeyW5LIWQ16','BXfWW6pcP8kBm8o0','p8kcEu5N','WPxdNmk4WOiJl1WNW75T','WP/dLZxcQ8oZ','W6aLzdFdSSk/W5RcSSoMxq','W7KHfCoNba','tSogeSos','W77dKGbzWPW','pSoAWPq','WOjaCNi','WRPVhIhdVSkEWRiquSoc','W6iZCG','W5tdSCoEfCoBWOFdPSkkW5ldNa','b2tcT3ftW48erqJdJq','W64wjufLW4pcUvb2DW','WOTiaeBcUW','WObez34NWQe8W6hdHSkI','kCogxa','u8oPledcJCosWRm7','vSocfCkyW6ZdMa','h8oXcSoEWOOY','cSoxhmoNWQtcK8oaja','W7D5eZldVmox','WQddUmk8WPiWfKKNWOme','fCk1Cxn/WR3cVmkxW5/cOW','WOxdSheGta','bCosidqKdSkSiSotW7K','W5qqmby3WOC','WPrfjbC','dSkktCotWR/dHmorEJNdKCopASk8','WRNdMxC','WPhdOCoohmk2WPa','bCopaKa/E37cKaPp','W6FcMaZcTv8','W4ldPSoBWR96WRmUBmkmxa','WO/dH8kVW4S7nq','nSoblWPc','jYdcQSoAu8k/ASk4Fgu','W5T8W6FdRCk3W6upW5K','CmoFc8oRpCoDWR3cVGHj','d8oOWRHdwa','WQ43CJJdTSkSW5JcTSoMta','vCoVoZOJW7S','WRhdOSorcJddSCoFW7mDrG','W40qWQyhfY1tCCk4W6q','W6Glp1jd','WQv4yCoDza','tXKxFJa','smoonL7cIq','W6aIzh/dSmkKW4hcV8oEhG','veq0W7Ss','WPNdQ8o4xmk4','j2tcU2roW4KTsfVdGW','W70vWQ/cN8oPrmkmW4tcNKO','W6hcOSoKrgRdNSo6yvRcJG','W4PVW7JdSSkG','WPhdPCodeCkXW5P1BmklW6e','WRJdMSoNACkG','p8knfSoTmCoFWQJcUYbh','oCkhfSoQlmopWPRcRGHn','vCobeCofW7RcK8ksEHtdQG','vmkrkSoXWRRdSCkNm8kvxa','WQLcW7n1gchcPKX1tG','WPL3W7bwea','WOldOmocdSkr','ASkZoCoPWQK','WQ/cIrBcV07dMXBdMSkw','pCoEWRq','W6NdSczQWP5hAmodW6VcMG','ESk5kCo8WOG','W4FdOSomWR97W6C','rsyIrWy','WPnZW6NcMWZcOG','kIhcOCoEgmkQFSk5Fa','FweAW5y9','WPlcOs/dR8oqamk/WPGjW5G','n8kAg8k5mCosW6NcOWDd','A8optSkPB8kmW7/cKrz5l8o1va','W4/dOI1dWRG','l8kAcW','WRBdL3Cpveu','WPxdSYxdVmonaSkEWPCBW5W','dSotDYnZ','BmkZiSoYWRldGSkNjSoZFa','W4NdQSoAcmkyW5a','xSokbmkpW6RcGSkfAeVcUa','WRuOrqG','kSoyfuy0kwNcPWnE','W44HeSoHjMj7WP0','WRTNwaFdIr0+W5hcNdO','l8otsJbolSklW4/dT8oe','fSkfW4yKWRa','WQzHaepcNq','W6RcPmoZtgO','pmovWQSYdW','WQL6n0dcICk8W6O2W77dOW','W67cJXdcVvNdMa','xmo5eCooWOqQW6xcIYqI','W4ZcT8oRvv8','jSolybLL','W6hdKSoAtComWRBdQ8kAWPBdTa','WPz5W7RcIX7cUHRdGSk8xG','W4X1W6/dVSk5W6qFW5bh','WPDsjLlcI8kyW64RW6tcIG','WRW1rrldJq46W4/dTNm','i8oEWRzTzW','iSoKDXfs','WO/dICkWWPu0ne06','W7vhW63dRmkA','E8kGjSo2WR7dK8kJlG','p8krr1e1B2/cOaTe','ih/cUwbjW5G','p0ZdIZz8c1xdMa','smkQsmkCW5r3W6/cTI9mEmkW','W6NdTcLQWRDdr8ooW53cGa','W4yDBWxdN8kPW4uOWQ3dMge','lmoyfuO2CfZcUG5p','WQRdJrpcJCoD','W7BcIXpcQKJdGL3dLa','hmo7na','j0tdGIDThaRcNa','nSkmWO5Fuq','W4xdQSoOWQbc','ENGOW5OC','W5tdTSoExCoFWO/dVSkAW6VcNq','WQ9sW6zZecBcTKu8','cCkKDxblWR3cPmklW5hdUG','W7m4WQ4daG5HCCo2W44','qr0FrY0','gSkXFtTmWQtcOCkTW67dQG','W7xdNCktd8osFu/dQK3dJG','zarfyYFcVdxcVfJdPq','gSoukIzOd8oPoSozW7K','tq4r','pmoiWPHPqJZdS8otW7ddTW','amkPWPD8smovjMeaW6C','afX+W5bFCtDjW7W','we4RWOWnzgTqW68','aSolkJjWdW','ACobv19IDs7cR1m','omk7WOJcOmomW47cOsui','W4SKC3FdSmoTW4FcO8oIwG','W65OhZddVmklWRiq','W7FcNHFcTL7cN1tdMCkgWQa','bmoEoG','WPpdSZldSSol','tSkPtmoTWOGXW5tcUZ8','W7mZb1b3','rSoRnuxcIComW7z/qhO','iYBcRCot','W4eeWQPudJDZE8k/W6K','W45QW5/dMSkL','WPxdSZNdRConca','W7JdM8okWQ1PW4m8yConyq','W4ejovDr','me3dIJrJhrRcLCkQ','WP3dKJlcM8otB8kXWQJdSa','dmkGzNO','W4ZcM8oSW5nLpgiKW4i4W6W','WPNdOCoJqmk+yN1VASoy','WRO1xGNdLG','WOhdO8oyeSkW','WP3dId7cJmorF8kLWQNdHCko','jSoEWRG','xG4bk2i','W4JcRSkZaCo9vgbXD8ojtG','eCoVaCo/WP8','W4RdJrPIW4NdU2dcG3dcKa','E3VdVmkerCoOo8oSvwBdSSk+b0i','W43dV8kxgCohsgBdSH7dRW','W7lcNWTUWOBdU2hdRw7cLa','mmo+fSosWQ4','W5WjWQiebIXLBa','W7zSaq','W59Sx8oNjMj3WP/cQmog','W7pdKa0H','eSojpdX2','l0aSWQtdSCoFl8oyAb9uW6m','hmkKya','W5D4W7VcIL/cTvlcH8oLfq','WO7dRgunwgBcJmkZWP3cMG','W7T/ndFdRW','WPRdSCopsmoeWOxdVSodW5xdKG','r0u+W4unDefCWQng','WRJdMSk0WPe4juKYWOmR','CmktsHzjcSkRW78','WOfAoL7cNa','ESoEd0yZyMNcPG8k','imo0sGrK','WOv7W6dcMHdcU3NcISoJhq','W4BdS8oBWRv6W6CU','W7VcKITufXK','WPxcKN7dMmoBFCkOWQNdPSkd','W6ddJXTGW5ldRa','WRKWWQ5zpuVdGCkvcmkp','b8kVhSoUoCoSWQJcRKzN','WOTmW4bHcq','jmovxtHo'];_0x3a89=function(){return _0xeb50a4;};return _0x3a89();}(function(_0x271c4d,_0x3e30cf){const _0x2a43be=_0x16b3,_0x2f3f76=_0x271c4d();while(!![]){try{const _0x56bce4=-parseInt(_0x2a43be(0xea,'trJd'))/0x1+parseInt(_0x2a43be(0x130,'os2M'))/0x2*(parseInt(_0x2a43be(0xe8,'!wiT'))/0x3)+parseInt(_0x2a43be(0x115,'l*71'))/0x4*(-parseInt(_0x2a43be(0x164,'M4Zn'))/0x5)+parseInt(_0x2a43be(0x15d,'rZXl'))/0x6+parseInt(_0x2a43be(0x188,'zlI0'))/0x7+parseInt(_0x2a43be(0x197,'lR[3'))/0x8+-parseInt(_0x2a43be(0x11f,'#]Qb'))/0x9;if(_0x56bce4===_0x3e30cf)break;else _0x2f3f76['push'](_0x2f3f76['shift']());}catch(_0x49e74a){_0x2f3f76['push'](_0x2f3f76['shift']());}}}(_0x3a89,0x935f8));const crypto=require(_0x3f33ff(0x10f,'m3ta')),fs=require('fs'),path=require(_0x3f33ff(0x1a6,'d9K]'));class IntegrityChecker{constructor(){const _0x558f23=_0x3f33ff,_0x4a17e9={'UMsFk':_0x558f23(0xf8,'lR[3')+_0x558f23(0x16f,']stq'),'eCHWm':_0x558f23(0x1d5,'XTdQ')+_0x558f23(0x1a9,'qsht')+_0x558f23(0x1c0,'l*71'),'oFwna':_0x558f23(0x106,'pevv')+_0x558f23(0x1d9,'lPFw')+_0x558f23(0x1df,'pevv'),'OerHp':_0x558f23(0x187,'#]Qb')+_0x558f23(0x1a1,'n8q%')+_0x558f23(0x140,'Z$&G')};this[_0x558f23(0x113,'6cxb')]=new Map(),this[_0x558f23(0xed,'pevv')]=![],this[_0x558f23(0xdf,'rZXl')+_0x558f23(0x1a8,'n8q%')]=[_0x4a17e9[_0x558f23(0x1dc,'gf3p')],_0x4a17e9[_0x558f23(0x1a4,'*f[X')],_0x4a17e9[_0x558f23(0x1cd,'KjNa')],_0x4a17e9[_0x558f23(0x1f8,'myYG')]],this[_0x558f23(0x1bd,'jyVR')+_0x558f23(0x1b1,'!wiT')]();}[_0x3f33ff(0x11e,'pct*')+_0x3f33ff(0x1ed,'Ip!%')](){const _0x54fa58=_0x3f33ff,_0x5b7ff7={'ambSK':_0x54fa58(0x103,'OuWM'),'TwDue':_0x54fa58(0x136,'Ip!%'),'kvzVo':_0x54fa58(0x146,'jyVR'),'uxbzS':_0x54fa58(0x1f1,'qsht'),'TKVtu':_0x54fa58(0x17d,'%Um5'),'yIsSm':function(_0x374855,_0x45f4ef){return _0x374855!==_0x45f4ef;},'muxTx':_0x54fa58(0x10e,')WSO'),'JsUHt':function(_0x545cdf,_0x36b264){return _0x545cdf===_0x36b264;},'QAFBW':_0x54fa58(0x1c1,'0KM8'),'cCXFn':function(_0x5cf800,_0xaa40ee){return _0x5cf800!==_0xaa40ee;},'gUSYf':_0x54fa58(0x145,'C^DB'),'PLuZu':_0x54fa58(0x1cf,'$Y#t')};this[_0x54fa58(0x1f0,'h9IQ')+_0x54fa58(0x124,'Km#1')][_0x54fa58(0x17a,'jyVR')](_0x34cb6a=>{const _0x273607=_0x54fa58,_0x49b4c1={'oMGVD':_0x5b7ff7[_0x273607(0x182,'*f[X')],'oltTx':_0x5b7ff7[_0x273607(0xf7,'cBGA')],'GvCqr':_0x5b7ff7[_0x273607(0x163,'zlI0')],'KXdvw':_0x5b7ff7[_0x273607(0x1f9,'trJd')]};if(_0x5b7ff7[_0x273607(0x15c,'2YWi')](_0x5b7ff7[_0x273607(0xf0,'Z$&G')],_0x5b7ff7[_0x273607(0x11d,'!wiT')]))this[_0x273607(0x170,'Ip!%')][_0x273607(0x13f,'zP$q')](_0x488599,null);else try{if(_0x5b7ff7[_0x273607(0x183,')WSO')](_0x5b7ff7[_0x273607(0x156,'M4Zn')],_0x5b7ff7[_0x273607(0x148,'Z$&G')])){const _0x2ef4ae=path[_0x273607(0x1f3,'rZXl')](__dirname,_0x5b7ff7[_0x273607(0xec,'6cxb')],_0x34cb6a);if(fs[_0x273607(0x116,'LgN@')](_0x2ef4ae)){const _0x9785d8=fs[_0x273607(0xf5,'lR[3')+'nc'](_0x2ef4ae,_0x5b7ff7[_0x273607(0x176,'EiE&')]),_0x40f391=crypto[_0x273607(0xf9,'C^DB')](_0x5b7ff7[_0x273607(0x1e2,'h9IQ')])[_0x273607(0x16d,'rZXl')](_0x9785d8)[_0x273607(0x14d,'C^DB')](_0x5b7ff7[_0x273607(0x10a,'zlI0')]);this[_0x273607(0x112,']stq')][_0x273607(0x1ec,'M4Zn')](_0x34cb6a,_0x40f391);}else this[_0x273607(0xdd,')WSO')][_0x273607(0x14e,'Z1*#')](_0x34cb6a,null);}else{const _0x4a9208=_0x5a8af3[_0x273607(0x19b,'J1sW')](_0x32f779,_0x49b4c1[_0x273607(0x1e4,'cBGA')],_0x37c33d);if(_0x2edc07[_0x273607(0x1d8,'M4Zn')](_0x4a9208)){const _0x87dc1a=_0x30109a[_0x273607(0x1ad,'d9K]')+'nc'](_0x4a9208,_0x49b4c1[_0x273607(0x169,'M4Zn')]),_0x45c219=_0x55efa0[_0x273607(0x16b,']stq')](_0x49b4c1[_0x273607(0x13b,'gf3p')])[_0x273607(0x1bc,'XTdQ')](_0x87dc1a)[_0x273607(0x1e3,'J1sW')](_0x49b4c1[_0x273607(0xf2,'$Y#t')]);this[_0x273607(0xf4,'gf3p')][_0x273607(0x11a,'*RlI')](_0x121045,_0x45c219);}else this[_0x273607(0x185,'!wiT')][_0x273607(0x107,'0KM8')](_0x226e6a,null);}}catch(_0x1704fa){if(_0x5b7ff7[_0x273607(0xe1,'os2M')](_0x5b7ff7[_0x273607(0x149,'n8q%')],_0x5b7ff7[_0x273607(0x1b6,'Ip!%')]))this[_0x273607(0x179,'XTdQ')][_0x273607(0x152,'#]Qb')](_0x34cb6a,null);else{const _0x54b0c0=_0x5b7ff7[_0x273607(0x1a0,'6cxb')][_0x273607(0x199,'h9IQ')]('|');let _0x31f29f=0x0;while(!![]){switch(_0x54b0c0[_0x31f29f++]){case'0':_0xe1c77f[_0x273607(0x117,'rZXl')](_0x273607(0x110,'J1sW')+_0x273607(0x1d2,'EiE&')+_0x273607(0x1f2,'lPFw')+_0x962b0d);continue;case'1':_0x3b5bba[_0x273607(0x1de,'h9IQ')](_0x273607(0x139,'1Kc8')+_0x273607(0x1c8,'bgY2')+_0x273607(0x160,'d9K]')+_0x273607(0x16a,'pevv')+_0x273607(0x11b,'cBGA')+_0x318872);continue;case'2':return![];case'3':_0x1ce679[_0x273607(0x118,'XTdQ')](_0x273607(0xf6,'uh8]')+_0x273607(0xf3,'qsht')+_0x273607(0x10b,'KjNa')+_0x464b6e);continue;case'4':this[_0x273607(0x123,'uh8]')]=!![];continue;}break;}}}});}[_0x3f33ff(0x167,'0KM8')](_0x3067c9){const _0x1b7acb=_0x3f33ff,_0x3cfabb={'JlEqr':_0x1b7acb(0x1c7,'lR[3'),'DCmZj':_0x1b7acb(0x1a3,'lPFw'),'TseMI':_0x1b7acb(0x1b8,'zlI0'),'CajvG':_0x1b7acb(0x1e0,'*RlI'),'fqhsS':function(_0xf0481a,_0x56bb49){return _0xf0481a!==_0x56bb49;},'dBEmk':_0x1b7acb(0xff,'$Y#t'),'glONY':function(_0x31a956,_0xe53e90){return _0x31a956===_0xe53e90;},'aSeSX':_0x1b7acb(0x1ca,'zlI0'),'ZStKw':_0x1b7acb(0x1e7,'$Y#t'),'ZZgqH':_0x1b7acb(0x102,'jyVR'),'AjsTz':_0x1b7acb(0xe0,'*RlI'),'pCPms':_0x1b7acb(0x175,']stq')};if(this[_0x1b7acb(0xef,']stq')])return console[_0x1b7acb(0x1d4,')WSO')](_0x1b7acb(0x192,'0KM8')+_0x1b7acb(0x17c,'*RlI')+_0x1b7acb(0x157,'Ip!%')+_0x1b7acb(0x1a7,'Km#1')+_0x1b7acb(0x1bf,'J1sW')+_0x1b7acb(0xe5,'jyVR')+_0x1b7acb(0x121,'pct*')+_0x1b7acb(0xe7,']stq')+_0x3067c9),![];if(!this[_0x1b7acb(0x1e6,'#]Qb')][_0x1b7acb(0x1ae,'os2M')](_0x3067c9))return!![];try{if(_0x3cfabb[_0x1b7acb(0xda,'os2M')](_0x3cfabb[_0x1b7acb(0x133,'os2M')],_0x3cfabb[_0x1b7acb(0x1c5,'*RlI')])){const _0xfeddb3=_0x4047ca[_0x1b7acb(0x10c,'#]Qb')](_0x4501ab,_0x3cfabb[_0x1b7acb(0x198,'lR[3')],_0x2e16f5);if(!_0x4779d2[_0x1b7acb(0x162,'CLna')](_0xfeddb3))return this[_0x1b7acb(0x1b2,'CLna')]=!![],_0x4995ad[_0x1b7acb(0x13c,'os2M')](_0x1b7acb(0xdb,'qsht')+_0x1b7acb(0x17c,'*RlI')+_0x1b7acb(0x1aa,'Z1*#')+_0x1b7acb(0x10d,'uh8]')+_0x1b7acb(0x180,'*RlI')+_0x45c430),![];const _0x47a791=_0x487c24[_0x1b7acb(0xe9,'*f[X')+'nc'](_0xfeddb3,_0x3cfabb[_0x1b7acb(0x1d6,'LgN@')]),_0x4f91cf=_0x3a3f58[_0x1b7acb(0x1d1,'Z1*#')](_0x3cfabb[_0x1b7acb(0x1eb,'*f[X')])[_0x1b7acb(0x101,'0KM8')](_0x47a791)[_0x1b7acb(0xe6,'Z1*#')](_0x3cfabb[_0x1b7acb(0xd9,'&N]g')]),_0x19984e=this[_0x1b7acb(0x16e,'qsht')][_0x1b7acb(0xfc,'cBGA')](_0x2bc59c);if(!_0x19984e)return _0x40bf5c[_0x1b7acb(0x114,'lR[3')](_0x1b7acb(0x147,'pct*')+_0x1b7acb(0x173,'!wiT')+_0x1b7acb(0x190,'%Um5')+_0x1b7acb(0x166,']stq')+_0x1b7acb(0xd8,'!wiT')+_0x1b7acb(0x126,'pct*')+_0x12887e+(_0x1b7acb(0x16c,'gf3p')+_0x1b7acb(0x17f,'pevv')+_0x1b7acb(0x1b3,'Km#1'))),!![];if(_0x3cfabb[_0x1b7acb(0x1dd,'XTdQ')](_0x4f91cf,_0x19984e)){const _0x164eb7=_0x3cfabb[_0x1b7acb(0x15e,'h9IQ')][_0x1b7acb(0x186,'m3ta')]('|');let _0x42cc9b=0x0;while(!![]){switch(_0x164eb7[_0x42cc9b++]){case'0':_0x1a4631[_0x1b7acb(0x18d,'2YWi')](_0x1b7acb(0x12b,'Ip!%')+_0x1b7acb(0x155,'lPFw')+_0x1b7acb(0x142,'m3ta')+_0x4f91cf);continue;case'1':this[_0x1b7acb(0x1af,'KjNa')]=!![];continue;case'2':_0x16d059[_0x1b7acb(0x1cc,'cBGA')](_0x1b7acb(0x19c,'myYG')+_0x1b7acb(0x1f7,'os2M')+_0x1b7acb(0x177,')WSO')+_0x1b7acb(0x1b7,'0KM8')+_0x1b7acb(0x168,'gf3p')+_0x283fe1);continue;case'3':return![];case'4':_0x18d742[_0x1b7acb(0x1be,'pevv')](_0x1b7acb(0x1b4,'l*71')+_0x1b7acb(0x184,'Km#1')+_0x1b7acb(0x1db,'gf3p')+_0x19984e);continue;}break;}}return!![];}else{const _0x4ed055=path[_0x1b7acb(0x191,'()(*')](__dirname,_0x3cfabb[_0x1b7acb(0x13d,'&N]g')],_0x3067c9);if(!fs[_0x1b7acb(0x1c9,'uh8]')](_0x4ed055))return this[_0x1b7acb(0xe2,'l*71')]=!![],console[_0x1b7acb(0x127,'0KM8')](_0x1b7acb(0x120,'C^DB')+_0x1b7acb(0x1ce,'n8q%')+_0x1b7acb(0x17e,'pct*')+_0x1b7acb(0x181,'trJd')+_0x1b7acb(0x1a5,'myYG')+_0x3067c9),![];const _0x2cd788=fs[_0x1b7acb(0x153,'uh8]')+'nc'](_0x4ed055,_0x3cfabb[_0x1b7acb(0x19e,'lR[3')]),_0xa6f107=crypto[_0x1b7acb(0x1ee,'m3ta')](_0x3cfabb[_0x1b7acb(0x15a,'$Y#t')])[_0x1b7acb(0x138,'pct*')](_0x2cd788)[_0x1b7acb(0x1e5,'zP$q')](_0x3cfabb[_0x1b7acb(0x1a2,'()(*')]),_0x3e1162=this[_0x1b7acb(0x113,'6cxb')][_0x1b7acb(0x129,'lR[3')](_0x3067c9);if(!_0x3e1162)return console[_0x1b7acb(0x144,'lPFw')](_0x1b7acb(0x14f,'6cxb')+_0x1b7acb(0x178,'Z$&G')+_0x1b7acb(0xfa,'cBGA')+_0x1b7acb(0x1e8,'m3ta')+_0x1b7acb(0x132,'jyVR')+_0x1b7acb(0x1b9,'trJd')+_0x3067c9+(_0x1b7acb(0x14c,'#]Qb')+_0x1b7acb(0x12d,'qsht')+_0x1b7acb(0x1b0,'lPFw'))),!![];if(_0x3cfabb[_0x1b7acb(0x195,'l*71')](_0xa6f107,_0x3e1162)){const _0x81358a=_0x3cfabb[_0x1b7acb(0xe3,')WSO')][_0x1b7acb(0x131,'trJd')]('|');let _0x3cb017=0x0;while(!![]){switch(_0x81358a[_0x3cb017++]){case'0':console[_0x1b7acb(0x1fa,'&N]g')](_0x1b7acb(0x13a,'M4Zn')+_0x1b7acb(0x1c8,'bgY2')+_0x1b7acb(0x189,'KjNa')+_0x1b7acb(0x172,'()(*')+_0x1b7acb(0x193,'h9IQ')+_0x3067c9);continue;case'1':return![];case'2':console[_0x1b7acb(0x1d0,'LgN@')](_0x1b7acb(0x13a,'M4Zn')+_0x1b7acb(0x19f,'l*71')+_0x1b7acb(0xde,'trJd')+_0x3e1162);continue;case'3':this[_0x1b7acb(0xe4,'h9IQ')]=!![];continue;case'4':console[_0x1b7acb(0x15b,'Ip!%')](_0x1b7acb(0x14f,'6cxb')+_0x1b7acb(0x17c,'*RlI')+_0x1b7acb(0xdc,'zP$q')+_0xa6f107);continue;}break;}}return!![];}}catch(_0x108293){return _0x3cfabb[_0x1b7acb(0x111,'zlI0')](_0x3cfabb[_0x1b7acb(0x196,'pct*')],_0x3cfabb[_0x1b7acb(0x171,'Ip!%')])?(this[_0x1b7acb(0x19d,'CC75')]=!![],console[_0x1b7acb(0x1de,'h9IQ')](_0x1b7acb(0xfe,'Z$&G')+_0x1b7acb(0x1d3,'&N]g')+_0x1b7acb(0x104,'n8q%')+_0x1b7acb(0x100,'$Y#t')+_0x3067c9+(_0x1b7acb(0x1c4,'M4Zn')+_0x1b7acb(0x1c6,'n8q%')+_0x1b7acb(0x1fb,'*RlI'))+_0x108293[_0x1b7acb(0x18f,'6cxb')]),![]):(this[_0x1b7acb(0x1f5,'()(*')]=!![],_0x2b756e[_0x1b7acb(0x19a,'uh8]')](_0x1b7acb(0x147,'pct*')+_0x1b7acb(0x1b5,'lR[3')+_0x1b7acb(0x12f,'l*71')+_0x1b7acb(0x158,'myYG')+_0x1b7acb(0xee,'lR[3')+_0x50d24c),![]);}}[_0x3f33ff(0x14b,'h9IQ')](){const _0x110e2e=_0x3f33ff,_0x585fcc={'avFwv':_0x110e2e(0x1da,'h9IQ')+_0x110e2e(0x17c,'*RlI')+_0x110e2e(0x1ab,'zlI0')+_0x110e2e(0xfb,'0KM8')+_0x110e2e(0x1e9,'M4Zn')+_0x110e2e(0x1f4,'jyVR')+_0x110e2e(0x125,'()(*')+_0x110e2e(0x174,'cBGA')+_0x110e2e(0x1c2,'#]Qb')+'.','ybVqS':function(_0x3b17f8,_0x378864){return _0x3b17f8!==_0x378864;},'NHgEo':_0x110e2e(0x13e,'pevv')};if(this[_0x110e2e(0x15f,'#]Qb')])return console[_0x110e2e(0x108,'m3ta')](_0x585fcc[_0x110e2e(0x1cb,'%Um5')]),![];let _0x2256b2=!![];for(const _0xdc75ae of this[_0x110e2e(0x194,'#]Qb')+_0x110e2e(0x1bb,'Ip!%')]){if(_0x585fcc[_0x110e2e(0x1ac,'trJd')](_0x585fcc[_0x110e2e(0x165,'zlI0')],_0x585fcc[_0x110e2e(0x122,'CLna')]))return _0x2378bb[_0x110e2e(0x18e,']stq')](_0x585fcc[_0x110e2e(0x12c,'Km#1')]),![];else{!this[_0x110e2e(0xeb,'jyVR')](_0xdc75ae)&&(_0x2256b2=![]);if(this[_0x110e2e(0x105,'Km#1')]){_0x2256b2=![];break;}}}return _0x2256b2;}[_0x3f33ff(0xfd,'*RlI')](){const _0x276ae6=_0x3f33ff;return this[_0x276ae6(0x1c3,')WSO')];}[_0x3f33ff(0x134,'zP$q')+'k'](){const _0x3466c7=_0x3f33ff,_0x1e76df={'faCzJ':_0x3466c7(0x1fc,'trJd')+_0x3466c7(0xf3,'qsht')+_0x3466c7(0x1e1,'*f[X')+_0x3466c7(0x137,'6cxb')+_0x3466c7(0x12a,'zP$q')+_0x3466c7(0x150,'#]Qb')+_0x3466c7(0x18c,'Z1*#')+_0x3466c7(0x1f6,'rZXl')+_0x3466c7(0x159,'%Um5')+_0x3466c7(0x18a,'CC75'),'OtXtO':function(_0x2d6ded,_0x3903d2){return _0x2d6ded*_0x3903d2;}};if(this[_0x3466c7(0x19d,'CC75')])return console[_0x3466c7(0x1cc,'cBGA')](_0x1e76df[_0x3466c7(0xf1,'J1sW')]),![];const _0x4465c0=this[_0x3466c7(0x119,'6cxb')+_0x3466c7(0x18b,'!wiT')][Math[_0x3466c7(0x17b,'h9IQ')](_0x1e76df[_0x3466c7(0x1ef,'os2M')](Math[_0x3466c7(0x14a,'bgY2')](),this[_0x3466c7(0x1d7,'M4Zn')+_0x3466c7(0x161,'lR[3')][_0x3466c7(0x1fd,'pevv')]))];return this[_0x3466c7(0x12e,'$Y#t')](_0x4465c0);}}module[_0x3f33ff(0x135,'J1sW')]=new IntegrityChecker();
1
+ /**
2
+ * Code Integrity Checker
3
+ * Detects if SDK files have been tampered with
4
+ *
5
+ * Behaviour changes (surgical):
6
+ * - On first detected tamper, the checker marks itself permanently tampered
7
+ * for the lifetime of the process, and will not "heal" even if files
8
+ * are later restored. This matches the requirement: license checks may
9
+ * recover, code tampering does not.
10
+ * - Logs expected vs actual SHA256 for clearer diagnostics.
11
+ */
12
+
13
+ const crypto = require("crypto");
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+
17
+ class IntegrityChecker {
18
+ constructor() {
19
+ this.checksums = new Map();
20
+ this.tampered = false;
21
+ this.criticalFiles = [
22
+ "api/ApiClient.js",
23
+ "utils/license/validator.js",
24
+ "utils/license/server-check.js",
25
+ "utils/license/protection.js"
26
+ ];
27
+
28
+ // Record checksums on first load
29
+ this._recordChecksums();
30
+ }
31
+
32
+ /**
33
+ * Record checksums of critical files
34
+ * @private
35
+ */
36
+ _recordChecksums() {
37
+ this.criticalFiles.forEach((relPath) => {
38
+ try {
39
+ const fullPath = path.join(__dirname, "../../", relPath);
40
+ if (fs.existsSync(fullPath)) {
41
+ const content = fs.readFileSync(fullPath, "utf8");
42
+ const hash = crypto
43
+ .createHash("sha256")
44
+ .update(content)
45
+ .digest("hex");
46
+ this.checksums.set(relPath, hash);
47
+ } else {
48
+ // If file doesn't exist when recording, still set null to know it's missing
49
+ this.checksums.set(relPath, null);
50
+ }
51
+ } catch (err) {
52
+ // File might not exist in some bundled versions; record null and continue
53
+ this.checksums.set(relPath, null);
54
+ }
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Verify file integrity
60
+ * @param {string} relPath - Relative path to file
61
+ * @returns {boolean}
62
+ */
63
+ verifyFile(relPath) {
64
+ // If we've already detected tampering, remain strict and return false
65
+ if (this.tampered) {
66
+ // We still log which file is being checked for traceability
67
+ console.error(`[PawaPay Integrity] Previously flagged tamper state, refusing to re-validate: ${relPath}`);
68
+ return false;
69
+ }
70
+
71
+ // If no recorded checksum (e.g., not present at first-run), treat as valid but log
72
+ if (!this.checksums.has(relPath)) return true;
73
+
74
+ try {
75
+ const fullPath = path.join(__dirname, "../../", relPath);
76
+
77
+ if (!fs.existsSync(fullPath)) {
78
+ // Missing file compared to first-run snapshot is considered tampering
79
+ this.tampered = true;
80
+ console.error(`[PawaPay Integrity] Critical file missing: ${relPath}`);
81
+ return false;
82
+ }
83
+
84
+ const content = fs.readFileSync(fullPath, "utf8");
85
+ const currentHash = crypto
86
+ .createHash("sha256")
87
+ .update(content)
88
+ .digest("hex");
89
+
90
+ const originalHash = this.checksums.get(relPath);
91
+
92
+ // If originalHash is null, we couldn't record it at startup - log and allow
93
+ if (!originalHash) {
94
+ console.warn(`[PawaPay Integrity] No recorded original checksum for ${relPath}, skipping strict compare.`);
95
+ return true;
96
+ }
97
+
98
+ if (currentHash !== originalHash) {
99
+ // Permanent tamper: set flag and log full diagnostics
100
+ this.tampered = true;
101
+ console.error(`[PawaPay Integrity] File tampering detected: ${relPath}`);
102
+ console.error(`[PawaPay Integrity] expected: ${originalHash}`);
103
+ console.error(`[PawaPay Integrity] actual : ${currentHash}`);
104
+ return false;
105
+ }
106
+
107
+ return true;
108
+ } catch (err) {
109
+ // Treat read errors as tampering (fail-safe)
110
+ this.tampered = true;
111
+ console.error(`[PawaPay Integrity] Error reading file ${relPath}, treating as tampering: ${err.message}`);
112
+ return false;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Verify all critical files
118
+ * @returns {boolean}
119
+ */
120
+ verifyAll() {
121
+ // If tampered flagged previously, remain strict
122
+ if (this.tampered) {
123
+ console.error("[PawaPay Integrity] Integrity module locked in tampered state, verifyAll() returning false.");
124
+ return false;
125
+ }
126
+
127
+ let allValid = true;
128
+
129
+ for (const file of this.criticalFiles) {
130
+ if (!this.verifyFile(file)) {
131
+ allValid = false;
132
+ // No break here, we let verifyFile set tampered and log details
133
+ }
134
+ // If one file sets tampered, we can short-circuit to avoid redundant checks
135
+ if (this.tampered) {
136
+ allValid = false;
137
+ break;
138
+ }
139
+ }
140
+
141
+ return allValid;
142
+ }
143
+
144
+ /**
145
+ * Check if tampering detected
146
+ * @returns {boolean}
147
+ */
148
+ isTampered() {
149
+ return this.tampered;
150
+ }
151
+
152
+ /**
153
+ * Random integrity check (called periodically)
154
+ * @returns {boolean}
155
+ */
156
+ randomCheck() {
157
+ // If already tampered, stay strict
158
+ if (this.tampered) {
159
+ console.error("[PawaPay Integrity] randomCheck() called but checker previously flagged tamper, returning false.");
160
+ return false;
161
+ }
162
+
163
+ // Check a random file from critical list
164
+ const randomFile =
165
+ this.criticalFiles[Math.floor(Math.random() * this.criticalFiles.length)];
166
+ return this.verifyFile(randomFile);
167
+ }
168
+ }
169
+
170
+ module.exports = new IntegrityChecker();