@zerothreatai/cli 1.0.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.
package/.env.prod ADDED
@@ -0,0 +1,2 @@
1
+ LICENSE_API=http://localhost:3201/api/license
2
+ CLOUD_API=https://api.zerothreat.ai/api/on-prem/license
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, zerothreatai
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # zerothreat-installer-cli
2
+
3
+ This is the on_prem installer cli project
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const menu_js_1 = __importDefault(require("./src/menu.js"));
9
+ const start_setup_js_1 = require("./src/commands/start-setup.js");
10
+ const dotenv_1 = require("dotenv");
11
+ (0, dotenv_1.config)({
12
+ path: !process.env.WORKING_ENVIRONMENT ? `.env.prod` : `.env`
13
+ });
14
+ commander_1.program
15
+ .name("zt")
16
+ .description("ZEROTHREAT AI CLI")
17
+ .version("1.0.0");
18
+ commander_1.program
19
+ .command("menu")
20
+ .description("Show main menu")
21
+ .action(menu_js_1.default);
22
+ commander_1.program.command("start-setup").action(start_setup_js_1.startSetup);
23
+ if (!process.argv.slice(2).length) {
24
+ (0, menu_js_1.default)();
25
+ }
26
+ else {
27
+ commander_1.program.parse(process.argv);
28
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.firstIgnition = firstIgnition;
7
+ exports.licenseDeactivate = licenseDeactivate;
8
+ const get_mac_1 = require("../utils/get-mac");
9
+ const path_1 = __importDefault(require("path"));
10
+ const child_process_1 = require("child_process");
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const js_yaml_1 = __importDefault(require("js-yaml"));
13
+ const dockerode_1 = __importDefault(require("dockerode"));
14
+ const license_api_service_1 = __importDefault(require("../services/license-api-service"));
15
+ const acr_token_service_1 = __importDefault(require("../services/acr-token-service"));
16
+ const ask_que_1 = require("../utils/ask-que");
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const cli_table3_1 = __importDefault(require("cli-table3"));
19
+ const app_constants_1 = require("../constants/app-constants");
20
+ let COMPOSE_FILE = "";
21
+ const PROJECT = "zerothreat";
22
+ const NETWORK = "zerothreat-onprem-nw";
23
+ let auth = {
24
+ username: "",
25
+ password: "",
26
+ serveraddress: "",
27
+ };
28
+ const docker = new dockerode_1.default();
29
+ async function ensureNetwork() {
30
+ const existing = await docker.listNetworks({ filters: { name: [NETWORK] } });
31
+ if (existing.length === 0) {
32
+ await docker.createNetwork({ Name: NETWORK, CheckDuplicate: true });
33
+ console.log(`Network created: ${NETWORK}`);
34
+ }
35
+ }
36
+ async function pullImages() {
37
+ const doc = js_yaml_1.default.load(fs_1.default.readFileSync(COMPOSE_FILE, "utf8"));
38
+ const images = Object.values(doc.services || {}).map(s => s.image);
39
+ console.log(`Pulling ${images.length} images in parallel...`);
40
+ await Promise.all(images.map(image => new Promise((resolve, reject) => {
41
+ docker.pull(image, { authconfig: auth }, (err, stream) => {
42
+ if (err)
43
+ return reject(err);
44
+ if (!stream)
45
+ return reject(new Error("No stream received"));
46
+ docker.modem.followProgress(stream, err => (err ? reject(err) : resolve()), () => process.stdout.write("."));
47
+ });
48
+ }).then(() => console.log(`\nDone: ${image}`))));
49
+ console.log("All images pulled!");
50
+ }
51
+ async function runCompose(args) {
52
+ return new Promise((resolve, reject) => {
53
+ const child = (0, child_process_1.spawn)("docker", ["compose", "-f", COMPOSE_FILE, "-p", PROJECT, ...args], {
54
+ stdio: "inherit",
55
+ });
56
+ child.on("close", code => (code === 0 ? resolve() : reject(new Error("compose failed"))));
57
+ });
58
+ }
59
+ async function firstIgnition(licenseKey, emailId) {
60
+ console.log(">> Running first docker setup ...");
61
+ let token = '';
62
+ const acrTokenService = new acr_token_service_1.default();
63
+ const machineId = (0, get_mac_1.getMachineId)();
64
+ try {
65
+ const { dockerAuth, activationToken } = await acrTokenService.getAcrToken(licenseKey, emailId, machineId);
66
+ auth = dockerAuth;
67
+ token = activationToken;
68
+ if (app_constants_1.dockerComposeAcr) {
69
+ COMPOSE_FILE = app_constants_1.dockerComposeAcr;
70
+ }
71
+ await ensureNetwork();
72
+ await pullImages();
73
+ await runCompose(["up", "-d"]);
74
+ //sleep for 30 seconds to allow sql server to start
75
+ console.log("Waiting for SQL Server to start...");
76
+ await new Promise(resolve => setTimeout(resolve, 30000));
77
+ }
78
+ catch (error) {
79
+ throw error;
80
+ }
81
+ finally {
82
+ if (app_constants_1.dockerComposeAcr) {
83
+ const tempDir = path_1.default.dirname(app_constants_1.dockerComposeAcr);
84
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
85
+ }
86
+ }
87
+ return token;
88
+ }
89
+ async function licenseDeactivate() {
90
+ console.log(chalk_1.default.dim("License deactivation initiated.. \n"));
91
+ try {
92
+ const deactivationToken = await (0, ask_que_1.ask)(chalk_1.default.yellow.bold("🗝️ Enter Deactivation Token: "));
93
+ const machineId = (0, get_mac_1.getMachineId)();
94
+ const licenseApi = new license_api_service_1.default();
95
+ const table = new cli_table3_1.default({
96
+ chars: {
97
+ "top": "═",
98
+ "top-left": "╔",
99
+ "top-right": "╗",
100
+ "bottom": "═",
101
+ "bottom-left": "╚",
102
+ "bottom-right": "╝",
103
+ "left": "║",
104
+ "right": "║",
105
+ },
106
+ });
107
+ try {
108
+ const res = await licenseApi.deactivateLicense(machineId, deactivationToken);
109
+ if (res.status) {
110
+ table.options.style.border = ['green'];
111
+ table.push([chalk_1.default.bold.green(res.message)]);
112
+ console.log(table.toString());
113
+ }
114
+ else {
115
+ table.push([chalk_1.default.bold.green(res.message)]);
116
+ console.log(table.toString());
117
+ }
118
+ }
119
+ catch (error) {
120
+ table.options.style.border = ['red'];
121
+ table.push([chalk_1.default.bold.red(`DeactivateLicense error:${error.message}`)]);
122
+ console.log(table.toString());
123
+ }
124
+ }
125
+ catch (err) {
126
+ console.log(chalk_1.default.redBright(`DeactivateLicense error: ${err.message}`));
127
+ }
128
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const license_api_service_1 = __importDefault(require("../services/license-api-service"));
7
+ const license_table_1 = require("../utils/license-table");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const cli_table3_1 = __importDefault(require("cli-table3"));
10
+ exports.default = async (token) => {
11
+ console.log(chalk_1.default.blue("\n🚀 Opening Activation Page...\n"));
12
+ const licenseService = new license_api_service_1.default();
13
+ const response = await licenseService.activateLicense(token);
14
+ if (response.status) {
15
+ // Celebration header
16
+ const table = new cli_table3_1.default({
17
+ style: {
18
+ border: ["blue"],
19
+ head: [],
20
+ compact: false,
21
+ },
22
+ chars: {
23
+ "top": chalk_1.default.green("═"),
24
+ "top-left": chalk_1.default.green("╔"),
25
+ "top-right": chalk_1.default.green("╗"),
26
+ "bottom": chalk_1.default.green("═"),
27
+ "bottom-left": chalk_1.default.green("╚"),
28
+ "bottom-right": chalk_1.default.green("╝"),
29
+ "left": chalk_1.default.green("║"),
30
+ "right": chalk_1.default.green("║"),
31
+ },
32
+ });
33
+ table.push([chalk_1.default.bold.green(' 🎉 CONGRATULATIONS! LICENSE ACTIVATED! 🎉')]);
34
+ console.log(table.toString());
35
+ console.log(chalk_1.default.green.bold('\n✨ Welcome to ZeroThreatAI Web Vulnerability Scan Platform! ✨'));
36
+ console.log(chalk_1.default.gray('Your license has been successfully activated and is ready to use.\n'));
37
+ (0, license_table_1.displayLicenseTable)(response);
38
+ }
39
+ else {
40
+ console.log(chalk_1.default.red.bold('\n🚫 License Activation Failed\n'));
41
+ console.log(chalk_1.default.gray('We were unable to connect to the ZeroThreatAI servers to complete the'));
42
+ console.log(chalk_1.default.gray('license activation. Please check the possible causes and try again.\n'));
43
+ console.log(chalk_1.default.bold('Reasons'));
44
+ console.log(chalk_1.default.red('📄 Reason'));
45
+ console.log(chalk_1.default.gray(` ${response.message}\n`));
46
+ console.log(chalk_1.default.bold('Possible Causes'));
47
+ console.log(chalk_1.default.magenta('📶 Internet Connection'));
48
+ console.log(chalk_1.default.gray(' Your device may have lost its connection to the internet.\n'));
49
+ console.log(chalk_1.default.magenta('💥 System Crash'));
50
+ console.log(chalk_1.default.gray(' Your computer may have shut down unexpectedly during the process.\n'));
51
+ console.log(chalk_1.default.magenta('🛡️ Firewall or Proxy'));
52
+ console.log(chalk_1.default.gray(' Network security settings may be blocking the connection.\n'));
53
+ console.log(chalk_1.default.bold('Next Steps'));
54
+ console.log(chalk_1.default.gray('You can retry the activation process or contact our support team for assistance.\n'));
55
+ }
56
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const license_service_1 = require("../actions/license-service");
4
+ exports.default = async () => {
5
+ console.log("\nLicense Deactivation\n");
6
+ await (0, license_service_1.licenseDeactivate)();
7
+ };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startSetup = startSetup;
7
+ const license_service_1 = require("../actions/license-service");
8
+ const ask_que_1 = require("../utils/ask-que");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const activate_1 = __importDefault(require("./activate"));
11
+ const acr_error_1 = __importDefault(require("../utils/acr-error"));
12
+ const validateEmail = (email) => {
13
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
14
+ return emailRegex.test(email);
15
+ };
16
+ const validateLicenseKey = (key) => {
17
+ const licenseRegex = /^[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}$/;
18
+ return licenseRegex.test(key);
19
+ };
20
+ async function startSetup() {
21
+ console.log("\nActivating License...\n");
22
+ let email;
23
+ do {
24
+ email = await (0, ask_que_1.ask)(chalk_1.default.yellow.bold("📧 Enter Email: "));
25
+ if (!validateEmail(email)) {
26
+ console.log("Invalid email format. Please try again.");
27
+ }
28
+ } while (!validateEmail(email));
29
+ let licenseKey;
30
+ do {
31
+ licenseKey = await (0, ask_que_1.ask)(chalk_1.default.yellow.bold("🗝️ Enter License Key (XXXX-XXXX-XXXX-XXXX): "));
32
+ if (!validateLicenseKey(licenseKey)) {
33
+ console.log("Invalid license key format. Must be XXXX-XXXX-XXXX-XXXX where X is a number.");
34
+ }
35
+ } while (!validateLicenseKey(licenseKey));
36
+ // Docker Setup
37
+ let token = '';
38
+ try {
39
+ token = await (0, license_service_1.firstIgnition)(licenseKey, email);
40
+ }
41
+ catch (err) {
42
+ if (err instanceof acr_error_1.default) {
43
+ console.log(chalk_1.default.red(`Error : ${err.message}`));
44
+ return;
45
+ }
46
+ console.error(chalk_1.default.redBright(`Error : ${err.message}`));
47
+ console.error(chalk_1.default.yellowBright(`Please Retry.`));
48
+ return;
49
+ }
50
+ // License Activation call
51
+ try {
52
+ console.log("Setting up your license ...");
53
+ await (0, activate_1.default)(token);
54
+ return;
55
+ }
56
+ catch (err) {
57
+ console.error(chalk_1.default.redBright(err));
58
+ return;
59
+ }
60
+ }
61
+ ;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.API_CONFIG = void 0;
4
+ const API_CONFIG = () => {
5
+ return {
6
+ licenseApi: process.env.LICENSE_API,
7
+ onPremLicenseCloudeApi: process.env.CLOUD_API,
8
+ };
9
+ };
10
+ exports.API_CONFIG = API_CONFIG;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setDockerComposeAcr = exports.setLicenseClaimed = exports.dockerComposeAcr = exports.isLicenseClaimed = void 0;
4
+ exports.isLicenseClaimed = false;
5
+ exports.dockerComposeAcr = '';
6
+ const setLicenseClaimed = (value) => {
7
+ exports.isLicenseClaimed = value;
8
+ };
9
+ exports.setLicenseClaimed = setLicenseClaimed;
10
+ const setDockerComposeAcr = (value) => {
11
+ exports.dockerComposeAcr = value;
12
+ };
13
+ exports.setDockerComposeAcr = setDockerComposeAcr;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = showMenu;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const start_setup_1 = require("./commands/start-setup");
10
+ const deactivate_1 = __importDefault(require("./commands/deactivate"));
11
+ async function showMenu() {
12
+ console.clear();
13
+ // Header with description
14
+ console.log(chalk_1.default.gray('╔' + '═'.repeat(78) + '╗'));
15
+ console.log(chalk_1.default.gray('║') + chalk_1.default.bold.magenta(' ZEROTHREAT ON-PREM INSTALLER ') + chalk_1.default.gray('║'));
16
+ console.log(chalk_1.default.gray('╠' + '═'.repeat(78) + '╣'));
17
+ console.log(chalk_1.default.gray('║') + ' '.repeat(78) + chalk_1.default.gray('║'));
18
+ console.log(chalk_1.default.gray('║') + chalk_1.default.bold.white(' AppSec without Noise or Complexity ') + chalk_1.default.gray('║'));
19
+ console.log(chalk_1.default.gray('║') + chalk_1.default.white(' Continuous Pentesting for Web Apps & APIs at Dev Speed ') + chalk_1.default.gray('║'));
20
+ console.log(chalk_1.default.gray('║') + ' '.repeat(78) + chalk_1.default.gray('║'));
21
+ console.log(chalk_1.default.gray('║') + chalk_1.default.gray(' Ship 10× faster with audit-ready compliance. ZeroThreat protects ') + chalk_1.default.gray('║'));
22
+ console.log(chalk_1.default.gray('║') + chalk_1.default.gray(' modern web apps & APIs through continuous pentesting, actionable ') + chalk_1.default.gray('║'));
23
+ console.log(chalk_1.default.gray('║') + chalk_1.default.gray(' insights, and coverage for 40,000+ vulnerabilities. ') + chalk_1.default.gray('║'));
24
+ console.log(chalk_1.default.gray('║') + ' '.repeat(78) + chalk_1.default.gray('║'));
25
+ console.log(chalk_1.default.gray('║') + chalk_1.default.bold.green(' 🛡️ On-Premise Installation Tool CLI ') + chalk_1.default.gray('║'));
26
+ console.log(chalk_1.default.gray('║') + ' '.repeat(78) + chalk_1.default.gray('║'));
27
+ console.log(chalk_1.default.gray('╚' + '═'.repeat(78) + '╝'));
28
+ console.log();
29
+ // Menu options box
30
+ console.log(chalk_1.default.gray('╔═ ' + chalk_1.default.bold.white('MAIN MENU') + ' ═' + '═'.repeat(65) + '╗'));
31
+ console.log(chalk_1.default.gray('║ ') + ' '.repeat(76) + chalk_1.default.gray('║'));
32
+ const { action } = await inquirer_1.default.prompt([
33
+ {
34
+ type: "list",
35
+ name: "action",
36
+ message: chalk_1.default.bold.cyan("Select an action:"),
37
+ choices: [
38
+ {
39
+ name: chalk_1.default.green("🔑 Activate License & Setup"),
40
+ value: "Start Setup"
41
+ },
42
+ {
43
+ name: chalk_1.default.redBright("⛔ Deassociate License & System"),
44
+ value: "Deactivate License"
45
+ },
46
+ {
47
+ name: chalk_1.default.yellow("🔄 Update License") + chalk_1.default.gray(" (Coming Soon)"),
48
+ value: "Update License (Coming Soon)",
49
+ },
50
+ {
51
+ name: chalk_1.default.white("❌ Exit"),
52
+ value: "Exit"
53
+ },
54
+ ],
55
+ loop: false,
56
+ prefix: "║",
57
+ },
58
+ ]);
59
+ console.log(chalk_1.default.gray('║') + ' '.repeat(78) + chalk_1.default.gray('║'));
60
+ console.log(chalk_1.default.gray('╚' + '═'.repeat(78) + '╝'));
61
+ switch (action) {
62
+ case "Start Setup":
63
+ await (0, start_setup_1.startSetup)();
64
+ break;
65
+ case "Deactivate License":
66
+ await (0, deactivate_1.default)();
67
+ break;
68
+ default:
69
+ console.log("Exiting...");
70
+ console.clear();
71
+ process.exit(0);
72
+ }
73
+ // Status separator
74
+ console.log();
75
+ console.log((0, chalk_1.default)('-'.repeat(80)));
76
+ console.log();
77
+ // Navigation box
78
+ console.log(chalk_1.default.gray('╔═ ' + chalk_1.default.bold.white('NEXT') + ' ═' + '═'.repeat(60) + '╗'));
79
+ console.log(chalk_1.default.gray('║ ') + ' '.repeat(66) + chalk_1.default.gray('║'));
80
+ const { close } = await inquirer_1.default.prompt([
81
+ {
82
+ type: "list",
83
+ name: "close",
84
+ message: " ",
85
+ choices: [
86
+ { name: chalk_1.default.white("🏠 Main Menu"), value: "menu" },
87
+ { name: chalk_1.default.red("🚪 Exit Application"), value: "Exit" }
88
+ ],
89
+ theme: {
90
+ style: {
91
+ highlight: chalk_1.default.bgBlue.white
92
+ }
93
+ }
94
+ },
95
+ ]);
96
+ console.log(chalk_1.default.green('└' + '─'.repeat(74) + '┘'));
97
+ switch (close) {
98
+ case "menu":
99
+ await showMenu();
100
+ break;
101
+ default:
102
+ console.log("Exiting...");
103
+ console.clear();
104
+ process.exit(0);
105
+ }
106
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const axios_1 = __importDefault(require("axios"));
7
+ const https_1 = __importDefault(require("https"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const os_1 = __importDefault(require("os"));
11
+ const crypto_1 = __importDefault(require("crypto"));
12
+ const acr_error_1 = __importDefault(require("../utils/acr-error"));
13
+ const app_constants_1 = require("../constants/app-constants");
14
+ const api_config_1 = require("../config/api-config");
15
+ const api_service_1 = __importDefault(require("./api-service"));
16
+ class AcrTokenService extends api_service_1.default {
17
+ constructor() {
18
+ super({
19
+ baseURL: (0, api_config_1.API_CONFIG)().onPremLicenseCloudeApi,
20
+ timeout: 15000,
21
+ });
22
+ }
23
+ async getAcrToken(licenseKey, emailId, systemId) {
24
+ try {
25
+ const httpsAgent = new https_1.default.Agent({
26
+ keepAlive: true,
27
+ family: 4,
28
+ rejectUnauthorized: false,
29
+ });
30
+ const api = axios_1.default.create({
31
+ httpsAgent,
32
+ timeout: 15000,
33
+ headers: { "Content-Type": "application/json" },
34
+ });
35
+ const response = await this.post('/acr-token', {
36
+ licenseKey,
37
+ emailId,
38
+ systemId
39
+ });
40
+ const { registry, username, password } = response.tokenInfo;
41
+ if (response.dockerComposeAcr) {
42
+ const decodedDockerComposeAcr = Buffer.from(response.dockerComposeAcr, 'base64').toString('utf-8');
43
+ const randomDir = crypto_1.default.randomBytes(8).toString('hex');
44
+ const randomFileName = crypto_1.default.randomBytes(8).toString('hex') + '.yml';
45
+ const tempDir = path_1.default.join(os_1.default.tmpdir(), randomDir);
46
+ fs_1.default.mkdirSync(tempDir, { recursive: true });
47
+ const filePath = path_1.default.join(tempDir, randomFileName);
48
+ fs_1.default.writeFileSync(filePath, decodedDockerComposeAcr);
49
+ (0, app_constants_1.setDockerComposeAcr)(filePath);
50
+ }
51
+ return {
52
+ dockerAuth: {
53
+ username,
54
+ password,
55
+ serveraddress: registry,
56
+ },
57
+ activationToken: response.activationToken
58
+ };
59
+ }
60
+ catch (error) {
61
+ throw new acr_error_1.default(`${error.message}`);
62
+ }
63
+ }
64
+ }
65
+ exports.default = AcrTokenService;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const axios_1 = __importDefault(require("axios"));
7
+ const https_1 = __importDefault(require("https"));
8
+ class ApiService {
9
+ client;
10
+ constructor(config) {
11
+ this.client = axios_1.default.create({
12
+ baseURL: config.baseURL,
13
+ timeout: config.timeout || 10000,
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ },
17
+ httpsAgent: new https_1.default.Agent({
18
+ rejectUnauthorized: false,
19
+ }),
20
+ });
21
+ }
22
+ async post(endpoint, data) {
23
+ try {
24
+ const response = await this.client.post(endpoint, data);
25
+ return response.data;
26
+ }
27
+ catch (error) {
28
+ throw this.handleError(error);
29
+ }
30
+ }
31
+ async get(endpoint) {
32
+ try {
33
+ const response = await this.client.get(endpoint);
34
+ return response.data;
35
+ }
36
+ catch (error) {
37
+ throw this.handleError(error);
38
+ }
39
+ }
40
+ handleError(error) {
41
+ if (error.response) {
42
+ return new Error(`${error.response.data?.message || 'Unknown error'}`);
43
+ }
44
+ if (error.request) {
45
+ return new Error('Network Error: No response received');
46
+ }
47
+ return new Error(`Request Error: ${error.message}`);
48
+ }
49
+ }
50
+ exports.default = ApiService;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LicenseType = exports.LicenseStatus = void 0;
7
+ const api_service_1 = __importDefault(require("./api-service"));
8
+ const api_config_1 = require("../config/api-config");
9
+ var LicenseStatus;
10
+ (function (LicenseStatus) {
11
+ LicenseStatus[LicenseStatus["Active"] = 1] = "Active";
12
+ LicenseStatus[LicenseStatus["Expired"] = 2] = "Expired";
13
+ LicenseStatus[LicenseStatus["InActive"] = 3] = "InActive";
14
+ LicenseStatus[LicenseStatus["ClaimRequested"] = 4] = "ClaimRequested";
15
+ LicenseStatus[LicenseStatus["Revoked"] = 5] = "Revoked";
16
+ })(LicenseStatus || (exports.LicenseStatus = LicenseStatus = {}));
17
+ var LicenseType;
18
+ (function (LicenseType) {
19
+ LicenseType[LicenseType["FreeCreditUniversal"] = 0] = "FreeCreditUniversal";
20
+ LicenseType[LicenseType["FreeCreditHostnameSpecific"] = 1] = "FreeCreditHostnameSpecific";
21
+ LicenseType[LicenseType["PaidCredit"] = 2] = "PaidCredit";
22
+ LicenseType[LicenseType["SubscriptionCredit"] = 3] = "SubscriptionCredit";
23
+ })(LicenseType || (exports.LicenseType = LicenseType = {}));
24
+ class LicenseApiService extends api_service_1.default {
25
+ constructor() {
26
+ super({
27
+ baseURL: (0, api_config_1.API_CONFIG)().licenseApi,
28
+ timeout: 15000,
29
+ });
30
+ }
31
+ //remove
32
+ async setupLicense(encryptedMachineId) {
33
+ return this.post(`/setup/${encryptedMachineId}`);
34
+ }
35
+ async getSystem() {
36
+ try {
37
+ const result = await this.get(`/system`);
38
+ return result;
39
+ }
40
+ catch (exception) {
41
+ return { id: '' };
42
+ }
43
+ }
44
+ async activateLicense(token) {
45
+ return this.post("/activate", { token });
46
+ }
47
+ async deactivateLicense(encryptedMachineId, deactivationToken) {
48
+ try {
49
+ const res = await this.post('/deassociate', {
50
+ machineId: encryptedMachineId,
51
+ token: deactivationToken,
52
+ });
53
+ return res;
54
+ }
55
+ catch (error) {
56
+ if (error.code === 'ECONNREFUSED') {
57
+ const fallbackService = new api_service_1.default({
58
+ baseURL: (0, api_config_1.API_CONFIG)().onPremLicenseCloudeApi,
59
+ timeout: 15000,
60
+ });
61
+ const res = await fallbackService.post('/deassociate', {
62
+ data: "",
63
+ machineId: encryptedMachineId,
64
+ token: deactivationToken,
65
+ });
66
+ return res;
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ }
72
+ exports.default = LicenseApiService;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const crypto_1 = __importDefault(require("crypto"));
7
+ class InstallerAppCryptoService {
8
+ IV_LEN = 12;
9
+ TAG_LEN = 16;
10
+ KEY_LEN = 32;
11
+ K1;
12
+ K2;
13
+ K3;
14
+ K4;
15
+ K5;
16
+ keys;
17
+ constructor() {
18
+ this.K1 = this.normalizeKey("3jv8_Ve3yTNwJjhSiMftBXpAkFtJLxSNaoJcBGztvUI");
19
+ this.K2 = this.normalizeKey("ZEl9PKemmf4w6wYcK3uFiFYrya9FJMA9UI_B0k_217A");
20
+ this.K3 = this.normalizeKey("ZDjIlSq44RcZHAdZFRpCRYtayxVkadiEEUZ6TmeP7jU");
21
+ this.K4 = this.normalizeKey("ucnRjVn7WghWSXnn4XpDjIEyzJ9ChPUUojrx4g7giWM");
22
+ this.K5 = this.normalizeKey("C0p4tWA7EJF6c2hdgiV3VDZbfRzXUWjPhesycqsA0aM");
23
+ this.keys = [this.K1, this.K2, this.K3, this.K4, this.K5];
24
+ }
25
+ encrypt(plain) {
26
+ const key = this.keys[Math.floor(Math.random() * this.keys.length)];
27
+ const iv = crypto_1.default.randomBytes(this.IV_LEN);
28
+ const cipher = crypto_1.default.createCipheriv("aes-256-gcm", key, iv, { authTagLength: this.TAG_LEN });
29
+ const ct = Buffer.concat([cipher.update(Buffer.from(plain, "utf8")), cipher.final()]);
30
+ const tag = cipher.getAuthTag();
31
+ return this.b64uEnc(Buffer.concat([iv, tag, ct]));
32
+ }
33
+ decrypt(token) {
34
+ let data;
35
+ try {
36
+ data = this.b64uDec(token);
37
+ }
38
+ catch {
39
+ throw new Error("Invalid token");
40
+ }
41
+ if (data.length <= this.IV_LEN + this.TAG_LEN)
42
+ throw new Error("Corrupt token");
43
+ const iv = data.slice(0, this.IV_LEN);
44
+ const tag = data.slice(this.IV_LEN, this.IV_LEN + this.TAG_LEN);
45
+ const ct = data.slice(this.IV_LEN + this.TAG_LEN);
46
+ for (const key of this.keys) {
47
+ try {
48
+ const decipher = crypto_1.default.createDecipheriv("aes-256-gcm", key, iv, { authTagLength: this.TAG_LEN });
49
+ decipher.setAuthTag(tag);
50
+ const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
51
+ return pt.toString("utf8");
52
+ }
53
+ catch {
54
+ // try next key
55
+ }
56
+ }
57
+ throw new Error("Unable to decrypt with any key");
58
+ }
59
+ generateKey() {
60
+ return this.b64uEnc(crypto_1.default.randomBytes(this.KEY_LEN));
61
+ }
62
+ b64uEnc(buf) {
63
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
64
+ }
65
+ b64uDec(s) {
66
+ s = s.replace(/-/g, "+").replace(/_/g, "/");
67
+ const pad = 4 - (s.length % 4);
68
+ if (pad !== 4)
69
+ s += "=".repeat(pad);
70
+ return Buffer.from(s, "base64");
71
+ }
72
+ normalizeKey(k) {
73
+ const buf = Buffer.isBuffer(k) ? k : this.b64uDec(k);
74
+ if (buf.length !== this.KEY_LEN)
75
+ throw new Error("Key must be 32 bytes.");
76
+ return buf;
77
+ }
78
+ }
79
+ exports.default = InstallerAppCryptoService;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class AcrTokenError extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ Object.setPrototypeOf(this, new.target.prototype);
7
+ }
8
+ }
9
+ exports.default = AcrTokenError;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ask = ask;
7
+ const readline_1 = __importDefault(require("readline"));
8
+ function ask(question) {
9
+ return new Promise((resolve) => {
10
+ const rl = readline_1.default.createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout,
13
+ });
14
+ rl.question(question, (answer) => {
15
+ rl.close();
16
+ resolve(answer.trim());
17
+ });
18
+ rl.on('SIGINT', () => {
19
+ rl.close();
20
+ console.log('\nExiting...');
21
+ process.exit(0);
22
+ });
23
+ });
24
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMachineId = void 0;
4
+ const node_machine_id_1 = require("node-machine-id");
5
+ const getMachineId = () => {
6
+ return (0, node_machine_id_1.machineIdSync)(true);
7
+ };
8
+ exports.getMachineId = getMachineId;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.displayLicenseTable = displayLicenseTable;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ function displayLicenseTable(response) {
10
+ const getStatusText = (status) => {
11
+ const map = {
12
+ 1: 'Active',
13
+ 2: 'Expired',
14
+ 3: 'Inactive',
15
+ 4: 'Revoked',
16
+ 5: 'Claim Requested',
17
+ };
18
+ return map[status] || '❓ Unknown';
19
+ };
20
+ const getTypeText = (type) => {
21
+ const map = {
22
+ 0: 'Free Credit Universal',
23
+ 1: 'Free Credit Hostname',
24
+ 2: 'Paid Credit',
25
+ 3: 'Subscription'
26
+ };
27
+ return map[type] || '❓ Unknown';
28
+ };
29
+ const table = new cli_table3_1.default({
30
+ head: [chalk_1.default.bold('Property'), chalk_1.default.bold('Value')],
31
+ style: {
32
+ border: ['gray'],
33
+ head: [],
34
+ compact: false
35
+ },
36
+ chars: { 'top': '═', 'top-mid': '╤', 'top-left': '╔', 'top-right': '╗',
37
+ 'bottom': '═', 'bottom-mid': '╧', 'bottom-left': '╚', 'bottom-right': '╝',
38
+ 'left': '║', 'left-mid': '╟', 'mid': '─', 'mid-mid': '┼',
39
+ 'right': '║', 'right-mid': '╢', 'middle': '│' }
40
+ });
41
+ table.push([chalk_1.default.cyan.bold('📄 License Name'), chalk_1.default.white(response.license.licenseName)], [chalk_1.default.cyan.bold('🔑 License Key'), chalk_1.default.white(response.license.licenseKey)], [chalk_1.default.cyan.bold('🏢 Organization'), chalk_1.default.white(response.organizationName)], [chalk_1.default.cyan.bold('🟢 Status'), chalk_1.default.green(getStatusText(response.license.licenseStatus))], [chalk_1.default.cyan.bold('📊 Plan Type'), chalk_1.default.white(getTypeText(response.license.licenseType))], [chalk_1.default.cyan.bold('📅 Expires At'), chalk_1.default.white(new Date(response.license.expiresAt).toLocaleDateString())]);
42
+ if (response.license.scanCredits > 0) {
43
+ table.push(['🔍 Scan Credits', chalk_1.default.yellow.bold(response.license.scanCredits.toString())]);
44
+ }
45
+ if (response.license.creditTargets > 0) {
46
+ table.push(['🎯 Target Credits', chalk_1.default.yellow.bold(response.license.creditTargets.toString())]);
47
+ }
48
+ if (response.license.freeCredits > 0) {
49
+ table.push(['🎁 Free Credits', chalk_1.default.yellow.bold(response.license.freeCredits.toString())]);
50
+ }
51
+ console.log(chalk_1.default.bold.blue('\n📊 LICENSE DETAILS'));
52
+ console.log(table.toString());
53
+ console.log(chalk_1.default.gray('➤ You can now start using ZeroThreat security features.\n'));
54
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = openBrowser;
4
+ const child_process_1 = require("child_process");
5
+ async function openBrowser(url) {
6
+ let chromePath;
7
+ switch (process.platform) {
8
+ case "win32":
9
+ chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
10
+ break;
11
+ case "darwin":
12
+ chromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
13
+ break;
14
+ case "linux":
15
+ chromePath = "/usr/bin/google-chrome";
16
+ break;
17
+ default:
18
+ throw new Error("Unsupported OS");
19
+ }
20
+ await new Promise((resolve, reject) => {
21
+ const child = (0, child_process_1.spawn)(chromePath, [url]);
22
+ child.on('error', (err) => {
23
+ reject(err);
24
+ });
25
+ child.on('exit', (code, signal) => {
26
+ resolve({ code, signal });
27
+ });
28
+ });
29
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@zerothreatai/cli",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "scripts": {
6
+ "build": "node build.js",
7
+ "start": "cross-env WORKING_ENVIRONMENT=DEV node dist/index.js",
8
+ "dev": "node build.js && cross-env WORKING_ENVIRONMENT=DEV node dist/index.js",
9
+ "link": "npm run build && npm link"
10
+ },
11
+ "keywords": [],
12
+ "author": "",
13
+ "license": "ISC",
14
+ "description": "",
15
+ "dependencies": {
16
+ "axios": "^0.27.2",
17
+ "chalk": "^4.1.2",
18
+ "cli-table3": "^0.6.5",
19
+ "commander": "^14.0.2",
20
+ "cross-env": "^10.1.0",
21
+ "dockerode": "^4.0.2",
22
+ "dotenv": "^17.2.3",
23
+ "figlet": "^1.9.4",
24
+ "inquirer": "^8.2.5",
25
+ "js-yaml": "^4.1.1",
26
+ "node-machine-id": "^1.1.12"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ ".env.prod"
31
+ ],
32
+ "bin": {
33
+ "zt": "./dist/index.js"
34
+ },
35
+ "devDependencies": {
36
+ "@types/chalk": "^2.2.4",
37
+ "@types/commander": "^2.12.5",
38
+ "@types/dockerode": "^3.3.46",
39
+ "@types/figlet": "^1.5.0",
40
+ "@types/inquirer": "^9.0.9",
41
+ "@types/js-yaml": "^4.0.0",
42
+ "@types/node": "^24.10.1",
43
+ "@types/ora": "^3.2.0",
44
+ "@types/prompt-sync": "^4.2.3",
45
+ "@types/readline-sync": "^1.4.8",
46
+ "ts-node": "^10.9.2",
47
+ "typescript": "^5.9.3"
48
+ }
49
+ }