@profullstack/threatcrush 0.2.0 → 0.2.1
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/dist/daemon.js +380 -82
- package/dist/daemon.js.map +1 -1
- package/dist/index.js +324 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3336,10 +3336,18 @@ var require_commander = __commonJS({
|
|
|
3336
3336
|
// src/core/state.ts
|
|
3337
3337
|
function initStateDB(dbPath = "/var/lib/threatcrush/state.db") {
|
|
3338
3338
|
if (db) return db;
|
|
3339
|
+
if (dbUnavailable) {
|
|
3340
|
+
throw new Error("state db unavailable (previous init failed)");
|
|
3341
|
+
}
|
|
3339
3342
|
try {
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
+
try {
|
|
3344
|
+
db = new import_better_sqlite3.default(dbPath);
|
|
3345
|
+
} catch {
|
|
3346
|
+
db = new import_better_sqlite3.default(":memory:");
|
|
3347
|
+
}
|
|
3348
|
+
} catch (err) {
|
|
3349
|
+
dbUnavailable = true;
|
|
3350
|
+
throw err;
|
|
3343
3351
|
}
|
|
3344
3352
|
db.pragma("journal_mode = WAL");
|
|
3345
3353
|
db.exec(`
|
|
@@ -3375,7 +3383,8 @@ function initStateDB(dbPath = "/var/lib/threatcrush/state.db") {
|
|
|
3375
3383
|
return db;
|
|
3376
3384
|
}
|
|
3377
3385
|
function insertEvent(event) {
|
|
3378
|
-
const database =
|
|
3386
|
+
const database = tryDb();
|
|
3387
|
+
if (!database) return -1;
|
|
3379
3388
|
const stmt = database.prepare(`
|
|
3380
3389
|
INSERT INTO events (timestamp, module, category, severity, message, source_ip, details)
|
|
3381
3390
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
@@ -3391,22 +3400,34 @@ function insertEvent(event) {
|
|
|
3391
3400
|
);
|
|
3392
3401
|
return result.lastInsertRowid;
|
|
3393
3402
|
}
|
|
3403
|
+
function tryDb() {
|
|
3404
|
+
if (db) return db;
|
|
3405
|
+
if (dbUnavailable) return null;
|
|
3406
|
+
try {
|
|
3407
|
+
return initStateDB();
|
|
3408
|
+
} catch {
|
|
3409
|
+
return null;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3394
3412
|
function getRecentEvents(limit = 50) {
|
|
3395
|
-
const database =
|
|
3413
|
+
const database = tryDb();
|
|
3414
|
+
if (!database) return [];
|
|
3396
3415
|
const rows = database.prepare(`
|
|
3397
3416
|
SELECT * FROM events ORDER BY timestamp DESC LIMIT ?
|
|
3398
3417
|
`).all(limit);
|
|
3399
3418
|
return rows.map(rowToEvent);
|
|
3400
3419
|
}
|
|
3401
3420
|
function getEventCount(since) {
|
|
3402
|
-
const database =
|
|
3421
|
+
const database = tryDb();
|
|
3422
|
+
if (!database) return 0;
|
|
3403
3423
|
if (since) {
|
|
3404
3424
|
return database.prepare(`SELECT COUNT(*) as count FROM events WHERE timestamp >= ?`).get(since.toISOString()).count;
|
|
3405
3425
|
}
|
|
3406
3426
|
return database.prepare(`SELECT COUNT(*) as count FROM events`).get().count;
|
|
3407
3427
|
}
|
|
3408
3428
|
function getThreatCount(since) {
|
|
3409
|
-
const database =
|
|
3429
|
+
const database = tryDb();
|
|
3430
|
+
if (!database) return 0;
|
|
3410
3431
|
const severities = "('medium','high','critical')";
|
|
3411
3432
|
if (since) {
|
|
3412
3433
|
return database.prepare(
|
|
@@ -3418,13 +3439,30 @@ function getThreatCount(since) {
|
|
|
3418
3439
|
).get().count;
|
|
3419
3440
|
}
|
|
3420
3441
|
function getTopSources(limit = 10) {
|
|
3421
|
-
const database =
|
|
3442
|
+
const database = tryDb();
|
|
3443
|
+
if (!database) return [];
|
|
3422
3444
|
return database.prepare(`
|
|
3423
3445
|
SELECT source_ip as ip, COUNT(*) as count FROM events
|
|
3424
3446
|
WHERE source_ip IS NOT NULL
|
|
3425
3447
|
GROUP BY source_ip ORDER BY count DESC LIMIT ?
|
|
3426
3448
|
`).all(limit);
|
|
3427
3449
|
}
|
|
3450
|
+
function getModuleState(module2, key) {
|
|
3451
|
+
const database = db || initStateDB();
|
|
3452
|
+
const row = database.prepare(`SELECT value FROM module_state WHERE module = ? AND key = ?`).get(module2, key);
|
|
3453
|
+
if (!row) return void 0;
|
|
3454
|
+
try {
|
|
3455
|
+
return JSON.parse(row.value);
|
|
3456
|
+
} catch {
|
|
3457
|
+
return row.value;
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
function setModuleState(module2, key, value) {
|
|
3461
|
+
const database = db || initStateDB();
|
|
3462
|
+
database.prepare(`
|
|
3463
|
+
INSERT OR REPLACE INTO module_state (module, key, value) VALUES (?, ?, ?)
|
|
3464
|
+
`).run(module2, key, JSON.stringify(value));
|
|
3465
|
+
}
|
|
3428
3466
|
function rowToEvent(row) {
|
|
3429
3467
|
return {
|
|
3430
3468
|
id: row.id,
|
|
@@ -3443,12 +3481,13 @@ function closeDB() {
|
|
|
3443
3481
|
db = null;
|
|
3444
3482
|
}
|
|
3445
3483
|
}
|
|
3446
|
-
var import_better_sqlite3, db;
|
|
3484
|
+
var import_better_sqlite3, db, dbUnavailable;
|
|
3447
3485
|
var init_state = __esm({
|
|
3448
3486
|
"src/core/state.ts"() {
|
|
3449
3487
|
"use strict";
|
|
3450
3488
|
import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
3451
3489
|
db = null;
|
|
3490
|
+
dbUnavailable = false;
|
|
3452
3491
|
}
|
|
3453
3492
|
});
|
|
3454
3493
|
|
|
@@ -8220,7 +8259,7 @@ var source_default = chalk;
|
|
|
8220
8259
|
|
|
8221
8260
|
// src/index.ts
|
|
8222
8261
|
var import_readline = __toESM(require("readline"));
|
|
8223
|
-
var
|
|
8262
|
+
var import_node_child_process7 = require("child_process");
|
|
8224
8263
|
var import_node_fs22 = require("fs");
|
|
8225
8264
|
var import_node_path15 = require("path");
|
|
8226
8265
|
var import_node_os8 = require("os");
|
|
@@ -10836,7 +10875,14 @@ async function pentestCommand(targetUrl) {
|
|
|
10836
10875
|
} catch (err) {
|
|
10837
10876
|
spinner.fail(`Failed to reach target: ${err.message}`);
|
|
10838
10877
|
console.log(source_default.gray(" Check the URL and try again.\n"));
|
|
10839
|
-
return
|
|
10878
|
+
return {
|
|
10879
|
+
type: "pentest",
|
|
10880
|
+
target: targetUrl,
|
|
10881
|
+
findings: [],
|
|
10882
|
+
severity_summary: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
|
|
10883
|
+
summary: `Failed to reach target: ${err.message}`,
|
|
10884
|
+
error: err.message
|
|
10885
|
+
};
|
|
10840
10886
|
}
|
|
10841
10887
|
const sqliSpinner = ora({ text: "Testing SQL injection vectors...", color: "green" }).start();
|
|
10842
10888
|
const sqliPayloads = ["' OR 1=1--", "1' UNION SELECT NULL--", "' AND '1'='1"];
|
|
@@ -11377,7 +11423,7 @@ async function sshConnect(options) {
|
|
|
11377
11423
|
}
|
|
11378
11424
|
|
|
11379
11425
|
// src/commands/daemon.ts
|
|
11380
|
-
var
|
|
11426
|
+
var import_node_child_process5 = require("child_process");
|
|
11381
11427
|
var import_node_fs18 = require("fs");
|
|
11382
11428
|
var import_node_path12 = require("path");
|
|
11383
11429
|
var import_node_fs19 = require("fs");
|
|
@@ -11581,6 +11627,7 @@ var IpcServer = class {
|
|
|
11581
11627
|
// src/daemon/module-host.ts
|
|
11582
11628
|
var import_node_fs16 = require("fs");
|
|
11583
11629
|
var import_node_path10 = require("path");
|
|
11630
|
+
var import_node_url = require("url");
|
|
11584
11631
|
var import_toml4 = __toESM(require_toml());
|
|
11585
11632
|
init_paths();
|
|
11586
11633
|
|
|
@@ -11721,21 +11768,143 @@ var LogWatcher = class {
|
|
|
11721
11768
|
}
|
|
11722
11769
|
};
|
|
11723
11770
|
|
|
11771
|
+
// src/daemon/watchers/journal-watcher.ts
|
|
11772
|
+
var import_node_child_process4 = require("child_process");
|
|
11773
|
+
init_state();
|
|
11774
|
+
var JournalWatcher = class _JournalWatcher {
|
|
11775
|
+
constructor(bus2) {
|
|
11776
|
+
this.bus = bus2;
|
|
11777
|
+
}
|
|
11778
|
+
bus;
|
|
11779
|
+
proc = null;
|
|
11780
|
+
buffer = "";
|
|
11781
|
+
moduleName = "user-journal";
|
|
11782
|
+
active = false;
|
|
11783
|
+
static isAvailable() {
|
|
11784
|
+
const probe = (0, import_node_child_process4.spawnSync)("journalctl", ["--user", "-n", "0", "--no-pager"], {
|
|
11785
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
11786
|
+
});
|
|
11787
|
+
return probe.status === 0;
|
|
11788
|
+
}
|
|
11789
|
+
start() {
|
|
11790
|
+
if (!_JournalWatcher.isAvailable()) return false;
|
|
11791
|
+
const child = (0, import_node_child_process4.spawn)(
|
|
11792
|
+
"journalctl",
|
|
11793
|
+
["--user", "-o", "json", "-f", "--since", "now"],
|
|
11794
|
+
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
11795
|
+
);
|
|
11796
|
+
if (!child.stdout) return false;
|
|
11797
|
+
child.stdout.setEncoding("utf-8");
|
|
11798
|
+
child.stdout.on("data", (chunk) => this.onData(chunk));
|
|
11799
|
+
child.on("exit", () => {
|
|
11800
|
+
this.proc = null;
|
|
11801
|
+
this.active = false;
|
|
11802
|
+
});
|
|
11803
|
+
this.proc = child;
|
|
11804
|
+
this.active = true;
|
|
11805
|
+
return true;
|
|
11806
|
+
}
|
|
11807
|
+
stop() {
|
|
11808
|
+
if (this.proc) {
|
|
11809
|
+
try {
|
|
11810
|
+
this.proc.kill("SIGTERM");
|
|
11811
|
+
} catch {
|
|
11812
|
+
}
|
|
11813
|
+
this.proc = null;
|
|
11814
|
+
}
|
|
11815
|
+
this.active = false;
|
|
11816
|
+
}
|
|
11817
|
+
isActive() {
|
|
11818
|
+
return this.active;
|
|
11819
|
+
}
|
|
11820
|
+
moduleNameValue() {
|
|
11821
|
+
return this.moduleName;
|
|
11822
|
+
}
|
|
11823
|
+
onData(chunk) {
|
|
11824
|
+
this.buffer += chunk;
|
|
11825
|
+
let idx;
|
|
11826
|
+
while ((idx = this.buffer.indexOf("\n")) >= 0) {
|
|
11827
|
+
const line = this.buffer.slice(0, idx);
|
|
11828
|
+
this.buffer = this.buffer.slice(idx + 1);
|
|
11829
|
+
if (!line.trim()) continue;
|
|
11830
|
+
this.handleLine(line);
|
|
11831
|
+
}
|
|
11832
|
+
}
|
|
11833
|
+
handleLine(line) {
|
|
11834
|
+
let entry;
|
|
11835
|
+
try {
|
|
11836
|
+
entry = JSON.parse(line);
|
|
11837
|
+
} catch {
|
|
11838
|
+
return;
|
|
11839
|
+
}
|
|
11840
|
+
const message = entry.MESSAGE;
|
|
11841
|
+
if (!message) return;
|
|
11842
|
+
const priority = parseInt(entry.PRIORITY ?? "6", 10);
|
|
11843
|
+
const severity = priorityToSeverity(priority);
|
|
11844
|
+
const ident = entry.SYSLOG_IDENTIFIER || entry._COMM || "journal";
|
|
11845
|
+
const bumpedSeverity = bumpForIdent(ident, message, severity);
|
|
11846
|
+
const event = {
|
|
11847
|
+
timestamp: realtimeToDate(entry.__REALTIME_TIMESTAMP) || /* @__PURE__ */ new Date(),
|
|
11848
|
+
module: this.moduleName,
|
|
11849
|
+
category: "system",
|
|
11850
|
+
severity: bumpedSeverity,
|
|
11851
|
+
message: `[${ident}] ${message}`.slice(0, 500)
|
|
11852
|
+
};
|
|
11853
|
+
try {
|
|
11854
|
+
insertEvent(event);
|
|
11855
|
+
} catch {
|
|
11856
|
+
}
|
|
11857
|
+
this.bus.publish(event);
|
|
11858
|
+
}
|
|
11859
|
+
};
|
|
11860
|
+
function priorityToSeverity(priority) {
|
|
11861
|
+
if (priority <= 2) return "critical";
|
|
11862
|
+
if (priority === 3) return "high";
|
|
11863
|
+
if (priority === 4) return "medium";
|
|
11864
|
+
if (priority === 5) return "low";
|
|
11865
|
+
return "info";
|
|
11866
|
+
}
|
|
11867
|
+
function bumpForIdent(ident, message, base) {
|
|
11868
|
+
if (/sudo/i.test(ident) && /authentication failure|incorrect password|FAILED/i.test(message)) {
|
|
11869
|
+
return "high";
|
|
11870
|
+
}
|
|
11871
|
+
if (/sshd/i.test(ident) && /failed|invalid user|break-in/i.test(message)) {
|
|
11872
|
+
return "high";
|
|
11873
|
+
}
|
|
11874
|
+
return base;
|
|
11875
|
+
}
|
|
11876
|
+
function realtimeToDate(rt) {
|
|
11877
|
+
if (!rt) return null;
|
|
11878
|
+
const us = parseInt(rt, 10);
|
|
11879
|
+
if (!Number.isFinite(us)) return null;
|
|
11880
|
+
return new Date(Math.floor(us / 1e3));
|
|
11881
|
+
}
|
|
11882
|
+
|
|
11724
11883
|
// src/daemon/module-host.ts
|
|
11884
|
+
init_state();
|
|
11725
11885
|
var ModuleHost = class {
|
|
11726
11886
|
constructor(bus2) {
|
|
11727
11887
|
this.bus = bus2;
|
|
11728
11888
|
bus2.on("event", (event) => {
|
|
11729
11889
|
const mod = this.modules.get(event.module);
|
|
11730
11890
|
if (mod) mod.events++;
|
|
11891
|
+
for (const hosted of this.modules.values()) {
|
|
11892
|
+
if (hosted.status !== "running" || !hosted.instance?.onEvent) continue;
|
|
11893
|
+
void hosted.instance.onEvent(event).catch((err) => {
|
|
11894
|
+
hosted.status = "error";
|
|
11895
|
+
hosted.detail = `onEvent failed: ${String(err.message || err)}`;
|
|
11896
|
+
this.bus.announceModule(hosted.name, "error", hosted.detail);
|
|
11897
|
+
});
|
|
11898
|
+
}
|
|
11731
11899
|
});
|
|
11732
11900
|
}
|
|
11733
11901
|
bus;
|
|
11734
11902
|
modules = /* @__PURE__ */ new Map();
|
|
11735
11903
|
logWatcher = null;
|
|
11904
|
+
journalWatcher = null;
|
|
11736
11905
|
async start() {
|
|
11737
11906
|
this.registerBuiltins();
|
|
11738
|
-
this.
|
|
11907
|
+
await this.discoverAndStartInstalled();
|
|
11739
11908
|
this.logWatcher = new LogWatcher(this.bus);
|
|
11740
11909
|
const watched = this.logWatcher.start();
|
|
11741
11910
|
for (const modName of this.logWatcher.activeModules()) {
|
|
@@ -11746,10 +11915,30 @@ var ModuleHost = class {
|
|
|
11746
11915
|
this.bus.announceModule(modName, "running", mod.detail);
|
|
11747
11916
|
}
|
|
11748
11917
|
}
|
|
11918
|
+
this.journalWatcher = new JournalWatcher(this.bus);
|
|
11919
|
+
if (this.journalWatcher.start()) {
|
|
11920
|
+
const mod = this.modules.get("user-journal");
|
|
11921
|
+
if (mod) {
|
|
11922
|
+
mod.status = "running";
|
|
11923
|
+
mod.detail = "tailing journalctl --user";
|
|
11924
|
+
this.bus.announceModule("user-journal", "running", mod.detail);
|
|
11925
|
+
}
|
|
11926
|
+
}
|
|
11749
11927
|
}
|
|
11750
11928
|
async stop() {
|
|
11751
11929
|
this.logWatcher?.stop();
|
|
11930
|
+
this.journalWatcher?.stop();
|
|
11752
11931
|
for (const mod of this.modules.values()) {
|
|
11932
|
+
try {
|
|
11933
|
+
if (mod.instance && mod.status === "running") {
|
|
11934
|
+
await mod.instance.stop();
|
|
11935
|
+
}
|
|
11936
|
+
} catch (err) {
|
|
11937
|
+
mod.status = "error";
|
|
11938
|
+
mod.detail = `stop failed: ${String(err.message || err)}`;
|
|
11939
|
+
this.bus.announceModule(mod.name, "error", mod.detail);
|
|
11940
|
+
continue;
|
|
11941
|
+
}
|
|
11753
11942
|
mod.status = "loaded";
|
|
11754
11943
|
this.bus.announceModule(mod.name, "stopped");
|
|
11755
11944
|
}
|
|
@@ -11765,12 +11954,14 @@ var ModuleHost = class {
|
|
|
11765
11954
|
registerBuiltins() {
|
|
11766
11955
|
const builtins = [
|
|
11767
11956
|
{ name: "log-watcher", version: "0.1.0", source: "builtin", status: "loaded", events: 0 },
|
|
11768
|
-
{ name: "ssh-guard", version: "0.1.0", source: "builtin", status: "loaded", events: 0 }
|
|
11957
|
+
{ name: "ssh-guard", version: "0.1.0", source: "builtin", status: "loaded", events: 0 },
|
|
11958
|
+
{ name: "user-journal", version: "0.1.0", source: "builtin", status: "loaded", events: 0 }
|
|
11769
11959
|
];
|
|
11770
11960
|
for (const m of builtins) this.modules.set(m.name, m);
|
|
11771
11961
|
}
|
|
11772
|
-
|
|
11962
|
+
async discoverAndStartInstalled() {
|
|
11773
11963
|
if (!(0, import_node_fs16.existsSync)(PATHS.moduleDir)) return;
|
|
11964
|
+
const configs = loadModuleConfigs(PATHS.confD);
|
|
11774
11965
|
const entries = (0, import_node_fs16.readdirSync)(PATHS.moduleDir, { withFileTypes: true });
|
|
11775
11966
|
for (const entry of entries) {
|
|
11776
11967
|
if (!entry.isDirectory()) continue;
|
|
@@ -11779,16 +11970,113 @@ var ModuleHost = class {
|
|
|
11779
11970
|
try {
|
|
11780
11971
|
const manifest = import_toml4.default.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf-8"));
|
|
11781
11972
|
const name = manifest.module?.name || entry.name;
|
|
11782
|
-
|
|
11973
|
+
const defaults = manifest.module?.config?.defaults || {};
|
|
11974
|
+
const config = {
|
|
11975
|
+
enabled: true,
|
|
11976
|
+
...defaults,
|
|
11977
|
+
...configs.get(name) || {}
|
|
11978
|
+
};
|
|
11979
|
+
const hosted = {
|
|
11783
11980
|
name,
|
|
11784
11981
|
version: manifest.module?.version || "0.0.0",
|
|
11785
11982
|
source: "installed",
|
|
11786
|
-
status: "loaded",
|
|
11787
|
-
events: 0
|
|
11983
|
+
status: config.enabled === false ? "disabled" : "loaded",
|
|
11984
|
+
events: 0,
|
|
11985
|
+
path: (0, import_node_path10.join)(PATHS.moduleDir, entry.name),
|
|
11986
|
+
config
|
|
11987
|
+
};
|
|
11988
|
+
this.modules.set(name, hosted);
|
|
11989
|
+
if (config.enabled === false) continue;
|
|
11990
|
+
await this.startInstalled(hosted);
|
|
11991
|
+
} catch (err) {
|
|
11992
|
+
const name = entry.name;
|
|
11993
|
+
this.modules.set(name, {
|
|
11994
|
+
name,
|
|
11995
|
+
version: "0.0.0",
|
|
11996
|
+
source: "installed",
|
|
11997
|
+
status: "error",
|
|
11998
|
+
events: 0,
|
|
11999
|
+
detail: `manifest load failed: ${String(err.message || err)}`,
|
|
12000
|
+
path: (0, import_node_path10.join)(PATHS.moduleDir, entry.name)
|
|
11788
12001
|
});
|
|
12002
|
+
}
|
|
12003
|
+
}
|
|
12004
|
+
}
|
|
12005
|
+
async startInstalled(hosted) {
|
|
12006
|
+
const entrypoint = this.installedEntrypoint(hosted.path);
|
|
12007
|
+
if (!entrypoint) {
|
|
12008
|
+
hosted.status = "loaded";
|
|
12009
|
+
hosted.detail = "no built entrypoint found; run npm install && npm run build in the module directory";
|
|
12010
|
+
return;
|
|
12011
|
+
}
|
|
12012
|
+
try {
|
|
12013
|
+
const imported = await import((0, import_node_url.pathToFileURL)(entrypoint).href);
|
|
12014
|
+
const exported = imported.default || imported.module || imported;
|
|
12015
|
+
const instance = typeof exported === "function" ? new exported() : exported;
|
|
12016
|
+
if (!this.isThreatCrushModule(instance)) {
|
|
12017
|
+
throw new Error("entrypoint does not export a ThreatCrush module");
|
|
12018
|
+
}
|
|
12019
|
+
hosted.instance = instance;
|
|
12020
|
+
await instance.init(this.contextFor(hosted));
|
|
12021
|
+
await instance.start();
|
|
12022
|
+
hosted.status = "running";
|
|
12023
|
+
hosted.detail = `started from ${entrypoint}`;
|
|
12024
|
+
this.bus.announceModule(hosted.name, "running", hosted.detail);
|
|
12025
|
+
} catch (err) {
|
|
12026
|
+
hosted.status = "error";
|
|
12027
|
+
hosted.detail = String(err.message || err);
|
|
12028
|
+
this.bus.announceModule(hosted.name, "error", hosted.detail);
|
|
12029
|
+
}
|
|
12030
|
+
}
|
|
12031
|
+
installedEntrypoint(modulePath) {
|
|
12032
|
+
const packageJson = (0, import_node_path10.join)(modulePath, "package.json");
|
|
12033
|
+
const candidates = [];
|
|
12034
|
+
if ((0, import_node_fs16.existsSync)(packageJson)) {
|
|
12035
|
+
try {
|
|
12036
|
+
const pkg = JSON.parse((0, import_node_fs16.readFileSync)(packageJson, "utf-8"));
|
|
12037
|
+
if (pkg.main) candidates.push((0, import_node_path10.join)(modulePath, pkg.main));
|
|
11789
12038
|
} catch {
|
|
11790
12039
|
}
|
|
11791
12040
|
}
|
|
12041
|
+
candidates.push((0, import_node_path10.join)(modulePath, "dist", "index.js"), (0, import_node_path10.join)(modulePath, "index.js"));
|
|
12042
|
+
return candidates.find((candidate) => (0, import_node_fs16.existsSync)(candidate)) || null;
|
|
12043
|
+
}
|
|
12044
|
+
isThreatCrushModule(value) {
|
|
12045
|
+
return Boolean(
|
|
12046
|
+
value && typeof value === "object" && typeof value.init === "function" && typeof value.start === "function" && typeof value.stop === "function"
|
|
12047
|
+
);
|
|
12048
|
+
}
|
|
12049
|
+
contextFor(hosted) {
|
|
12050
|
+
return {
|
|
12051
|
+
config: hosted.config || { enabled: true },
|
|
12052
|
+
logger: this.loggerFor(hosted.name),
|
|
12053
|
+
emit: (event) => this.bus.publish(event),
|
|
12054
|
+
subscribe: (eventType, handler) => {
|
|
12055
|
+
this.bus.on("event", (event) => {
|
|
12056
|
+
if (event.category === eventType || event.module === eventType) handler(event);
|
|
12057
|
+
});
|
|
12058
|
+
},
|
|
12059
|
+
alert: (alert) => {
|
|
12060
|
+
this.bus.emit("alert", alert.event || {
|
|
12061
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
12062
|
+
module: hosted.name,
|
|
12063
|
+
category: "system",
|
|
12064
|
+
severity: alert.severity,
|
|
12065
|
+
message: alert.title,
|
|
12066
|
+
details: alert.body ? { body: alert.body } : void 0
|
|
12067
|
+
});
|
|
12068
|
+
},
|
|
12069
|
+
getState: (key) => getModuleState(hosted.name, key),
|
|
12070
|
+
setState: (key, value) => setModuleState(hosted.name, key, value)
|
|
12071
|
+
};
|
|
12072
|
+
}
|
|
12073
|
+
loggerFor(moduleName) {
|
|
12074
|
+
return {
|
|
12075
|
+
debug: (msg, ...args) => console.debug(`[${moduleName}] ${msg}`, ...args),
|
|
12076
|
+
info: (msg, ...args) => console.info(`[${moduleName}] ${msg}`, ...args),
|
|
12077
|
+
warn: (msg, ...args) => console.warn(`[${moduleName}] ${msg}`, ...args),
|
|
12078
|
+
error: (msg, ...args) => console.error(`[${moduleName}] ${msg}`, ...args)
|
|
12079
|
+
};
|
|
11792
12080
|
}
|
|
11793
12081
|
};
|
|
11794
12082
|
|
|
@@ -12211,7 +12499,7 @@ async function daemonStart() {
|
|
|
12211
12499
|
}
|
|
12212
12500
|
const out = (0, import_node_fs19.openSync)(PATHS.logFile, "a");
|
|
12213
12501
|
const err = (0, import_node_fs19.openSync)(PATHS.logFile, "a");
|
|
12214
|
-
const child = (0,
|
|
12502
|
+
const child = (0, import_node_child_process5.spawn)(process.execPath, [DAEMON_ENTRY], {
|
|
12215
12503
|
detached: true,
|
|
12216
12504
|
stdio: ["ignore", out, err],
|
|
12217
12505
|
env: { ...process.env, THREATCRUSH_DAEMON: "1" }
|
|
@@ -12276,7 +12564,7 @@ async function daemonStop() {
|
|
|
12276
12564
|
}
|
|
12277
12565
|
|
|
12278
12566
|
// src/commands/service.ts
|
|
12279
|
-
var
|
|
12567
|
+
var import_node_child_process6 = require("child_process");
|
|
12280
12568
|
var import_node_fs20 = require("fs");
|
|
12281
12569
|
var import_node_path13 = require("path");
|
|
12282
12570
|
var UNIT_PATH = "/etc/systemd/system/threatcrushd.service";
|
|
@@ -12291,7 +12579,7 @@ function resolveBinPath() {
|
|
|
12291
12579
|
const arg = process.argv[1];
|
|
12292
12580
|
if (arg && (0, import_node_fs20.existsSync)(arg)) return arg;
|
|
12293
12581
|
try {
|
|
12294
|
-
return (0,
|
|
12582
|
+
return (0, import_node_child_process6.execSync)("command -v threatcrush", { encoding: "utf-8" }).trim();
|
|
12295
12583
|
} catch {
|
|
12296
12584
|
return "threatcrush";
|
|
12297
12585
|
}
|
|
@@ -12313,8 +12601,8 @@ async function installServiceCommand() {
|
|
|
12313
12601
|
(0, import_node_fs20.writeFileSync)(UNIT_PATH, unit, { mode: 420 });
|
|
12314
12602
|
console.log(source_default.green(` \u2713 Installed unit file: ${UNIT_PATH}`));
|
|
12315
12603
|
try {
|
|
12316
|
-
(0,
|
|
12317
|
-
(0,
|
|
12604
|
+
(0, import_node_child_process6.execSync)("systemctl daemon-reload", { stdio: "inherit" });
|
|
12605
|
+
(0, import_node_child_process6.execSync)("systemctl enable threatcrushd.service", { stdio: "inherit" });
|
|
12318
12606
|
console.log(source_default.green(" \u2713 Service enabled on boot."));
|
|
12319
12607
|
console.log(source_default.dim(" Start now with: systemctl start threatcrushd"));
|
|
12320
12608
|
console.log(source_default.dim(" View logs with: journalctl -u threatcrushd -f"));
|
|
@@ -12333,22 +12621,22 @@ async function uninstallServiceCommand() {
|
|
|
12333
12621
|
return;
|
|
12334
12622
|
}
|
|
12335
12623
|
try {
|
|
12336
|
-
(0,
|
|
12624
|
+
(0, import_node_child_process6.execSync)("systemctl stop threatcrushd.service", { stdio: "inherit" });
|
|
12337
12625
|
} catch {
|
|
12338
12626
|
}
|
|
12339
12627
|
try {
|
|
12340
|
-
(0,
|
|
12628
|
+
(0, import_node_child_process6.execSync)("systemctl disable threatcrushd.service", { stdio: "inherit" });
|
|
12341
12629
|
} catch {
|
|
12342
12630
|
}
|
|
12343
12631
|
try {
|
|
12344
12632
|
if ((0, import_node_fs20.existsSync)(UNIT_PATH)) {
|
|
12345
|
-
(0,
|
|
12633
|
+
(0, import_node_child_process6.execSync)(`rm -f ${UNIT_PATH}`);
|
|
12346
12634
|
console.log(source_default.green(` \u2713 Removed unit file: ${UNIT_PATH}`));
|
|
12347
12635
|
}
|
|
12348
12636
|
} catch {
|
|
12349
12637
|
}
|
|
12350
12638
|
try {
|
|
12351
|
-
(0,
|
|
12639
|
+
(0, import_node_child_process6.execSync)("systemctl daemon-reload", { stdio: "inherit" });
|
|
12352
12640
|
} catch {
|
|
12353
12641
|
}
|
|
12354
12642
|
console.log(source_default.green(" \u2713 threatcrushd service removed."));
|
|
@@ -12908,22 +13196,22 @@ var DESKTOP_PKG_NAME = "@profullstack/threatcrush-desktop";
|
|
|
12908
13196
|
var INSTALL_CONFIG_PATH = (0, import_node_path15.join)((0, import_node_os8.homedir)(), ".threatcrush", "install.json");
|
|
12909
13197
|
function detectPackageManager() {
|
|
12910
13198
|
try {
|
|
12911
|
-
const npmGlobal = (0,
|
|
13199
|
+
const npmGlobal = (0, import_node_child_process7.execSync)("npm ls -g --depth=0 --json 2>/dev/null", { encoding: "utf-8" });
|
|
12912
13200
|
if (npmGlobal.includes(PKG_NAME)) return "npm";
|
|
12913
13201
|
} catch {
|
|
12914
13202
|
}
|
|
12915
13203
|
try {
|
|
12916
|
-
(0,
|
|
13204
|
+
(0, import_node_child_process7.execSync)("pnpm --version", { stdio: "pipe" });
|
|
12917
13205
|
return "pnpm";
|
|
12918
13206
|
} catch {
|
|
12919
13207
|
}
|
|
12920
13208
|
try {
|
|
12921
|
-
(0,
|
|
13209
|
+
(0, import_node_child_process7.execSync)("yarn --version", { stdio: "pipe" });
|
|
12922
13210
|
return "yarn";
|
|
12923
13211
|
} catch {
|
|
12924
13212
|
}
|
|
12925
13213
|
try {
|
|
12926
|
-
(0,
|
|
13214
|
+
(0, import_node_child_process7.execSync)("bun --version", { stdio: "pipe" });
|
|
12927
13215
|
return "bun";
|
|
12928
13216
|
} catch {
|
|
12929
13217
|
}
|
|
@@ -12969,7 +13257,7 @@ function packageLooksInstalled(pm, pkgName) {
|
|
|
12969
13257
|
yarn: `yarn global list --pattern ${pkgName}`,
|
|
12970
13258
|
bun: `bun pm ls -g`
|
|
12971
13259
|
};
|
|
12972
|
-
const output = (0,
|
|
13260
|
+
const output = (0, import_node_child_process7.execSync)(listCommands[pm] || listCommands.npm, {
|
|
12973
13261
|
encoding: "utf-8",
|
|
12974
13262
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12975
13263
|
});
|
|
@@ -13071,7 +13359,7 @@ program2.command("logs").description("Tail daemon logs").action(async () => {
|
|
|
13071
13359
|
console.log(source_default.green(` Tailing ${logPath}...
|
|
13072
13360
|
`));
|
|
13073
13361
|
console.log(source_default.gray(" Press Ctrl+C to stop\n"));
|
|
13074
|
-
(0,
|
|
13362
|
+
(0, import_node_child_process7.execSync)(`tail -f ${logPath}`, { stdio: "inherit" });
|
|
13075
13363
|
});
|
|
13076
13364
|
program2.command("activate").description("Activate your license key").action(async () => {
|
|
13077
13365
|
console.log(LOGO2);
|
|
@@ -13121,7 +13409,7 @@ program2.command("update").description("Update ThreatCrush CLI and installed bun
|
|
|
13121
13409
|
for (const cmd of commands2) {
|
|
13122
13410
|
console.log(source_default.green(` \u2192 ${cmd}
|
|
13123
13411
|
`));
|
|
13124
|
-
(0,
|
|
13412
|
+
(0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
|
|
13125
13413
|
}
|
|
13126
13414
|
console.log(source_default.green("\n \u2713 Modules updated successfully!\n"));
|
|
13127
13415
|
} catch (err) {
|
|
@@ -13147,7 +13435,7 @@ program2.command("update").description("Update ThreatCrush CLI and installed bun
|
|
|
13147
13435
|
for (const cmd of commands) {
|
|
13148
13436
|
console.log(source_default.green(` \u2192 ${cmd}
|
|
13149
13437
|
`));
|
|
13150
|
-
(0,
|
|
13438
|
+
(0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
|
|
13151
13439
|
}
|
|
13152
13440
|
console.log(source_default.green("\n \u2713 ThreatCrush updated successfully!\n"));
|
|
13153
13441
|
if (installMode === "desktop") {
|
|
@@ -13191,7 +13479,7 @@ program2.command("remove").description("Uninstall ThreatCrush and the installed
|
|
|
13191
13479
|
for (const cmd of commands) {
|
|
13192
13480
|
console.log(source_default.green(` \u2192 ${cmd}
|
|
13193
13481
|
`));
|
|
13194
|
-
(0,
|
|
13482
|
+
(0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
|
|
13195
13483
|
}
|
|
13196
13484
|
console.log(source_default.green("\n \u2713 ThreatCrush has been uninstalled.\n"));
|
|
13197
13485
|
console.log(source_default.dim(" We're sorry to see you go! \u{1F44B}\n"));
|