lucifer-gate 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/server/cli.js +220 -0
- package/dist/server/cli.js.map +1 -0
- package/dist/server/create_app.js +95 -0
- package/dist/server/create_app.js.map +1 -0
- package/dist/server/domains/command-gateway/api/register_execute_routes.js +338 -0
- package/dist/server/domains/command-gateway/api/register_execute_routes.js.map +1 -0
- package/dist/server/domains/command-gateway/config/gateway_config.js +46 -0
- package/dist/server/domains/command-gateway/config/gateway_config.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/api_key_store.js +44 -0
- package/dist/server/domains/command-gateway/repository/api_key_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/approval_store.js +83 -0
- package/dist/server/domains/command-gateway/repository/approval_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/audit_log.js +24 -0
- package/dist/server/domains/command-gateway/repository/audit_log.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/command_rules_store.js +42 -0
- package/dist/server/domains/command-gateway/repository/command_rules_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/database.js +59 -0
- package/dist/server/domains/command-gateway/repository/database.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/pending_request_store.js +61 -0
- package/dist/server/domains/command-gateway/repository/pending_request_store.js.map +1 -0
- package/dist/server/domains/command-gateway/service/analyze_command_risk.js +44 -0
- package/dist/server/domains/command-gateway/service/analyze_command_risk.js.map +1 -0
- package/dist/server/domains/command-gateway/service/authenticate_request.js +71 -0
- package/dist/server/domains/command-gateway/service/authenticate_request.js.map +1 -0
- package/dist/server/domains/command-gateway/service/auto_approve_channel.js +24 -0
- package/dist/server/domains/command-gateway/service/auto_approve_channel.js.map +1 -0
- package/dist/server/domains/command-gateway/service/execute_command.js +139 -0
- package/dist/server/domains/command-gateway/service/execute_command.js.map +1 -0
- package/dist/server/domains/command-gateway/service/request_telegram_approval.js +126 -0
- package/dist/server/domains/command-gateway/service/request_telegram_approval.js.map +1 -0
- package/dist/server/domains/command-gateway/types/command_types.js +2 -0
- package/dist/server/domains/command-gateway/types/command_types.js.map +1 -0
- package/dist/server/domains/command-gateway/types/store_interfaces.js +2 -0
- package/dist/server/domains/command-gateway/types/store_interfaces.js.map +1 -0
- package/dist/server/domains/platform-api/api/register_health_routes.js +6 -0
- package/dist/server/domains/platform-api/api/register_health_routes.js.map +1 -0
- package/dist/server/domains/platform-api/config/server_config.js +17 -0
- package/dist/server/domains/platform-api/config/server_config.js.map +1 -0
- package/dist/server/domains/platform-api/repository/runtime_metadata_repository.js +7 -0
- package/dist/server/domains/platform-api/repository/runtime_metadata_repository.js.map +1 -0
- package/dist/server/domains/platform-api/service/create_health_report.js +10 -0
- package/dist/server/domains/platform-api/service/create_health_report.js.map +1 -0
- package/dist/server/domains/platform-api/types/health_report.js +2 -0
- package/dist/server/domains/platform-api/types/health_report.js.map +1 -0
- package/dist/server/index.js +18 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lib/json_config_loader.js +31 -0
- package/dist/server/lib/json_config_loader.js.map +1 -0
- package/dist/server/lib/logger.js +12 -0
- package/dist/server/lib/logger.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
5
|
+
const log = createChildLogger('database');
|
|
6
|
+
let db = null;
|
|
7
|
+
export function getDatabase(dataDir) {
|
|
8
|
+
if (db)
|
|
9
|
+
return db;
|
|
10
|
+
const dbPath = resolve(dataDir, 'lucifer.db');
|
|
11
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
12
|
+
log.info({ dbPath }, 'Opening SQLite database');
|
|
13
|
+
db = new Database(dbPath, { fileMustExist: false });
|
|
14
|
+
db.pragma('journal_mode = WAL');
|
|
15
|
+
db.pragma('busy_timeout = 5000');
|
|
16
|
+
db.exec(`
|
|
17
|
+
CREATE TABLE IF NOT EXISTS approvals (
|
|
18
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
19
|
+
command TEXT NOT NULL,
|
|
20
|
+
match_type TEXT NOT NULL CHECK (match_type IN ('exact', 'prefix')),
|
|
21
|
+
duration TEXT NOT NULL,
|
|
22
|
+
approved_at TEXT NOT NULL,
|
|
23
|
+
expires_at TEXT,
|
|
24
|
+
approved_by TEXT NOT NULL
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_approvals_command ON approvals (command);
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_approvals_expires ON approvals (expires_at);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE IF NOT EXISTS audit_log (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
ts TEXT NOT NULL,
|
|
33
|
+
type TEXT NOT NULL,
|
|
34
|
+
request_id TEXT NOT NULL,
|
|
35
|
+
command TEXT,
|
|
36
|
+
api_key_name TEXT,
|
|
37
|
+
ip TEXT,
|
|
38
|
+
rule_action TEXT,
|
|
39
|
+
duration TEXT,
|
|
40
|
+
approved_by TEXT,
|
|
41
|
+
exit_code INTEGER,
|
|
42
|
+
duration_ms INTEGER,
|
|
43
|
+
error TEXT
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_audit_request_id ON audit_log (request_id);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_audit_ts ON audit_log (ts);
|
|
48
|
+
`);
|
|
49
|
+
log.info('Database schema initialized');
|
|
50
|
+
return db;
|
|
51
|
+
}
|
|
52
|
+
export function closeDatabase() {
|
|
53
|
+
if (db) {
|
|
54
|
+
db.close();
|
|
55
|
+
db = null;
|
|
56
|
+
log.info('Database closed');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/repository/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,GAAG,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;AAE1C,IAAI,EAAE,GAA6B,IAAI,CAAC;AAExC,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IAElB,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAChD,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAEjC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCP,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACxC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,EAAE,EAAE,CAAC;QACP,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,EAAE,GAAG,IAAI,CAAC;QACV,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
2
|
+
const log = createChildLogger('pending-requests');
|
|
3
|
+
export function createPendingRequestStore() {
|
|
4
|
+
const store = new Map();
|
|
5
|
+
return {
|
|
6
|
+
add(request) {
|
|
7
|
+
store.set(request.requestId, request);
|
|
8
|
+
log.debug({ requestId: request.requestId, command: request.command }, 'Pending request added');
|
|
9
|
+
},
|
|
10
|
+
resolve(requestId, decision) {
|
|
11
|
+
const pending = store.get(requestId);
|
|
12
|
+
if (!pending) {
|
|
13
|
+
log.debug({ requestId }, 'Resolve called for unknown/expired request');
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
pending.resolve(decision);
|
|
17
|
+
store.delete(requestId);
|
|
18
|
+
log.info({ requestId, decision }, 'Pending request resolved');
|
|
19
|
+
return true;
|
|
20
|
+
},
|
|
21
|
+
get(requestId) {
|
|
22
|
+
return store.get(requestId);
|
|
23
|
+
},
|
|
24
|
+
remove(requestId) {
|
|
25
|
+
const pending = store.get(requestId);
|
|
26
|
+
if (pending) {
|
|
27
|
+
pending.abortController.abort();
|
|
28
|
+
store.delete(requestId);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
findByCommand(command, apiKeyName) {
|
|
32
|
+
for (const pending of store.values()) {
|
|
33
|
+
if (pending.command === command && pending.apiKeyName === apiKeyName) {
|
|
34
|
+
return pending;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
},
|
|
39
|
+
cleanup(maxAgeMs) {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
let removed = 0;
|
|
42
|
+
for (const [id, pending] of store.entries()) {
|
|
43
|
+
const age = now - new Date(pending.createdAt).getTime();
|
|
44
|
+
if (age > maxAgeMs) {
|
|
45
|
+
pending.reject(new Error('Approval timed out'));
|
|
46
|
+
pending.abortController.abort();
|
|
47
|
+
store.delete(id);
|
|
48
|
+
removed++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (removed > 0) {
|
|
52
|
+
log.info({ removed }, 'Stale pending requests cleaned up');
|
|
53
|
+
}
|
|
54
|
+
return removed;
|
|
55
|
+
},
|
|
56
|
+
size() {
|
|
57
|
+
return store.size;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=pending_request_store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending_request_store.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/repository/pending_request_store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,GAAG,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;AAYlD,MAAM,UAAU,yBAAyB;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEhD,OAAO;QACL,GAAG,CAAC,OAAuB;YACzB,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACtC,GAAG,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,uBAAuB,CAAC,CAAC;QACjG,CAAC;QAED,OAAO,CAAC,SAAiB,EAAE,QAA0B;YACnD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,4CAA4C,CAAC,CAAC;gBACvE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,0BAA0B,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,GAAG,CAAC,SAAiB;YACnB,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9B,CAAC;QAED,MAAM,CAAC,SAAiB;YACtB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACrC,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;gBAChC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,aAAa,CAAC,OAAe,EAAE,UAAkB;YAC/C,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;oBACrE,OAAO,OAAO,CAAC;gBACjB,CAAC;YACH,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,CAAC,QAAgB;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC5C,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;gBACxD,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;oBACnB,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;oBAChD,OAAO,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;oBAChC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACjB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAChB,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,mCAAmC,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI;YACF,OAAO,KAAK,CAAC,IAAI,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const DANGER_PATTERNS = [
|
|
2
|
+
{ pattern: /\|/, warning: 'Pipe (|) detected: output is passed to another command' },
|
|
3
|
+
{ pattern: /&&/, warning: 'Chained command (&&): runs a second command on success' },
|
|
4
|
+
{ pattern: /;/, warning: 'Semicolon (;): runs multiple commands sequentially' },
|
|
5
|
+
{ pattern: /`[^`]*`/, warning: 'Backtick command substitution detected' },
|
|
6
|
+
{ pattern: /\$\(/, warning: 'Command substitution $() detected' },
|
|
7
|
+
{ pattern: />>?\s/, warning: 'Output redirect (>) detected: writes to file' },
|
|
8
|
+
{ pattern: /<\s/, warning: 'Input redirect (<) detected' },
|
|
9
|
+
{ pattern: /\brm\s+-r/, warning: 'Recursive delete (rm -r) detected' },
|
|
10
|
+
{ pattern: /\bsudo\b/, warning: 'sudo: runs with elevated privileges' },
|
|
11
|
+
{ pattern: /\bcurl\b.*\|\s*\b(bash|sh|zsh)\b/, warning: 'curl piped to shell: remote code execution' },
|
|
12
|
+
{ pattern: /\beval\b/, warning: 'eval: executes dynamically constructed commands' },
|
|
13
|
+
];
|
|
14
|
+
const WARNING_PATTERNS = [
|
|
15
|
+
{ pattern: /\bdd\b/, warning: 'dd: disk/device operations' },
|
|
16
|
+
{ pattern: /\bchmod\b/, warning: 'chmod: changes file permissions' },
|
|
17
|
+
{ pattern: /\bchown\b/, warning: 'chown: changes file ownership' },
|
|
18
|
+
{ pattern: /\bmkfs\b/, warning: 'mkfs: formats filesystem' },
|
|
19
|
+
{ pattern: /\bkill\b/, warning: 'kill: terminates processes' },
|
|
20
|
+
];
|
|
21
|
+
export function analyzeCommandRisk(command) {
|
|
22
|
+
const warnings = [];
|
|
23
|
+
let hasDanger = false;
|
|
24
|
+
for (const { pattern, warning } of DANGER_PATTERNS) {
|
|
25
|
+
if (pattern.test(command)) {
|
|
26
|
+
warnings.push(warning);
|
|
27
|
+
hasDanger = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const { pattern, warning } of WARNING_PATTERNS) {
|
|
31
|
+
if (pattern.test(command)) {
|
|
32
|
+
warnings.push(warning);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let level = 'safe';
|
|
36
|
+
if (hasDanger) {
|
|
37
|
+
level = 'danger';
|
|
38
|
+
}
|
|
39
|
+
else if (warnings.length > 0) {
|
|
40
|
+
level = 'warning';
|
|
41
|
+
}
|
|
42
|
+
return { level, warnings };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=analyze_command_risk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze_command_risk.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/analyze_command_risk.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAgD;IACnE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,wDAAwD,EAAE;IACpF,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,wDAAwD,EAAE;IACpF,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,oDAAoD,EAAE;IAC/E,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,wCAAwC,EAAE;IACzE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mCAAmC,EAAE;IACjE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,8CAA8C,EAAE;IAC7E,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,EAAE;IAC1D,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,mCAAmC,EAAE;IACtE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,qCAAqC,EAAE;IACvE,EAAE,OAAO,EAAE,kCAAkC,EAAE,OAAO,EAAE,4CAA4C,EAAE;IACtG,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iDAAiD,EAAE;CACpF,CAAC;AAEF,MAAM,gBAAgB,GAAgD;IACpE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,4BAA4B,EAAE;IAC5D,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,iCAAiC,EAAE;IACpE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,+BAA+B,EAAE;IAClE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,0BAA0B,EAAE;IAC5D,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,4BAA4B,EAAE;CAC/D,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,eAAe,EAAE,CAAC;QACnD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,gBAAgB,EAAE,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,GAA+B,MAAM,CAAC;IAC/C,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,GAAG,QAAQ,CAAC;IACnB,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,GAAG,SAAS,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
2
|
+
const log = createChildLogger('auth');
|
|
3
|
+
export function createRateLimiter(maxPerMinute) {
|
|
4
|
+
return { counts: new Map(), maxPerMinute };
|
|
5
|
+
}
|
|
6
|
+
export function checkRateLimit(state, keyName) {
|
|
7
|
+
const now = Date.now();
|
|
8
|
+
const windowMs = 60_000;
|
|
9
|
+
const entry = state.counts.get(keyName);
|
|
10
|
+
if (!entry || now - entry.windowStart > windowMs) {
|
|
11
|
+
state.counts.set(keyName, { count: 1, windowStart: now });
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
entry.count++;
|
|
15
|
+
return entry.count <= state.maxPerMinute;
|
|
16
|
+
}
|
|
17
|
+
export function authenticateRequest(apiKeyStore, rateLimiter, rawKey, ip) {
|
|
18
|
+
if (!rawKey) {
|
|
19
|
+
log.warn({ ip }, 'Missing API key');
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
statusCode: 401,
|
|
23
|
+
error: { code: 'MISSING_API_KEY', message: 'x-api-key header is required', retryable: false },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const keyConfig = apiKeyStore.findByKey(rawKey);
|
|
27
|
+
if (!keyConfig) {
|
|
28
|
+
log.warn({ ip }, 'Invalid API key');
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
statusCode: 401,
|
|
32
|
+
error: { code: 'INVALID_API_KEY', message: 'Invalid API key', retryable: false },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (keyConfig.allowedIps && keyConfig.allowedIps.length > 0) {
|
|
36
|
+
const allowed = keyConfig.allowedIps.some(allowedIp => {
|
|
37
|
+
if (allowedIp.includes('/')) {
|
|
38
|
+
return ipInCidr(ip, allowedIp);
|
|
39
|
+
}
|
|
40
|
+
return ip === allowedIp;
|
|
41
|
+
});
|
|
42
|
+
if (!allowed) {
|
|
43
|
+
log.warn({ ip, keyName: keyConfig.name }, 'IP not in allowlist');
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
statusCode: 403,
|
|
47
|
+
error: { code: 'IP_NOT_ALLOWED', message: 'IP address not in allowlist', retryable: false },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!checkRateLimit(rateLimiter, keyConfig.name)) {
|
|
52
|
+
log.warn({ keyName: keyConfig.name, ip }, 'Rate limit exceeded');
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
statusCode: 429,
|
|
56
|
+
error: { code: 'RATE_LIMITED', message: 'Rate limit exceeded. Try again later.', retryable: true },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { ok: true, keyConfig };
|
|
60
|
+
}
|
|
61
|
+
function ipInCidr(ip, cidr) {
|
|
62
|
+
const [network, bits] = cidr.split('/');
|
|
63
|
+
const mask = ~(2 ** (32 - Number(bits)) - 1);
|
|
64
|
+
const ipNum = ipToInt(ip);
|
|
65
|
+
const netNum = ipToInt(network);
|
|
66
|
+
return (ipNum & mask) === (netNum & mask);
|
|
67
|
+
}
|
|
68
|
+
function ipToInt(ip) {
|
|
69
|
+
return ip.split('.').reduce((acc, octet) => (acc << 8) + Number(octet), 0) >>> 0;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=authenticate_request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authenticate_request.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/authenticate_request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
2
|
+
const log = createChildLogger('auto-approve');
|
|
3
|
+
export function createAutoApproveChannel() {
|
|
4
|
+
return {
|
|
5
|
+
async requestApproval(command, apiKeyName, ip, requestId, riskAnalysis) {
|
|
6
|
+
log.info({ requestId, command, apiKeyName, ip, risk: riskAnalysis.level }, 'AUTO-APPROVE: Command approved without Telegram');
|
|
7
|
+
if (riskAnalysis.warnings.length > 0) {
|
|
8
|
+
log.warn({ requestId, warnings: riskAnalysis.warnings }, 'Risk warnings (auto-approved)');
|
|
9
|
+
}
|
|
10
|
+
const decision = 'approved';
|
|
11
|
+
const matchType = 'exact';
|
|
12
|
+
const duration = '2';
|
|
13
|
+
return { decision, matchType, duration };
|
|
14
|
+
},
|
|
15
|
+
async start() {
|
|
16
|
+
log.warn('Running in AUTO-APPROVE mode. All commands will be approved without Telegram confirmation.');
|
|
17
|
+
log.warn('This mode is for development only. Do not use in production.');
|
|
18
|
+
},
|
|
19
|
+
async stop() {
|
|
20
|
+
// nothing to clean up
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=auto_approve_channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto_approve_channel.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/auto_approve_channel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;AAE9C,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,KAAK,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY;YACpE,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,EAChE,iDAAiD,CAClD,CAAC;YACF,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,+BAA+B,CAAC,CAAC;YAC5F,CAAC;YACD,MAAM,QAAQ,GAAqB,UAAU,CAAC;YAC9C,MAAM,SAAS,GAAsB,OAAO,CAAC;YAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC;YACrB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QAC3C,CAAC;QAED,KAAK,CAAC,KAAK;YACT,GAAG,CAAC,IAAI,CAAC,4FAA4F,CAAC,CAAC;YACvG,GAAG,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;QAC3E,CAAC;QAED,KAAK,CAAC,IAAI;YACR,sBAAsB;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
3
|
+
const log = createChildLogger('executor');
|
|
4
|
+
let activeExecutions = 0;
|
|
5
|
+
export async function executeCommand(options) {
|
|
6
|
+
const { command, requestId, cwd, timeoutMs, maxOutputBytes, maxConcurrent, abortSignal } = options;
|
|
7
|
+
if (activeExecutions >= maxConcurrent) {
|
|
8
|
+
log.warn({ requestId, active: activeExecutions, max: maxConcurrent }, 'Max concurrent executions reached');
|
|
9
|
+
return {
|
|
10
|
+
requestId,
|
|
11
|
+
status: 'failed',
|
|
12
|
+
error: 'Too many concurrent commands. Try again later.',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
activeExecutions++;
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
log.info({ requestId, command, cwd }, 'Executing command');
|
|
18
|
+
try {
|
|
19
|
+
return await new Promise((resolve) => {
|
|
20
|
+
const child = spawn(command, { shell: true, cwd: cwd ?? process.cwd(), detached: true });
|
|
21
|
+
let stdout = '';
|
|
22
|
+
let stderr = '';
|
|
23
|
+
let outputBytes = 0;
|
|
24
|
+
let killed = false;
|
|
25
|
+
const timer = setTimeout(() => {
|
|
26
|
+
killed = true;
|
|
27
|
+
try {
|
|
28
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
child.kill('SIGKILL');
|
|
32
|
+
}
|
|
33
|
+
log.warn({ requestId, timeoutMs }, 'Command timed out');
|
|
34
|
+
}, timeoutMs);
|
|
35
|
+
const onAbort = () => {
|
|
36
|
+
killed = true;
|
|
37
|
+
try {
|
|
38
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
child.kill('SIGKILL');
|
|
42
|
+
}
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
log.info({ requestId }, 'Command aborted (client disconnected)');
|
|
45
|
+
};
|
|
46
|
+
if (abortSignal) {
|
|
47
|
+
if (abortSignal.aborted) {
|
|
48
|
+
try {
|
|
49
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
child.kill('SIGKILL');
|
|
53
|
+
}
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
resolve({ requestId, status: 'failed', error: 'Request aborted' });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
abortSignal.addEventListener('abort', onAbort, { once: true });
|
|
59
|
+
}
|
|
60
|
+
child.stdout.on('data', (chunk) => {
|
|
61
|
+
outputBytes += chunk.length;
|
|
62
|
+
if (outputBytes <= maxOutputBytes) {
|
|
63
|
+
stdout += chunk.toString();
|
|
64
|
+
}
|
|
65
|
+
else if (!killed) {
|
|
66
|
+
killed = true;
|
|
67
|
+
try {
|
|
68
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
child.kill('SIGKILL');
|
|
72
|
+
}
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
log.warn({ requestId, outputBytes, maxOutputBytes }, 'Output buffer exceeded');
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
child.stderr.on('data', (chunk) => {
|
|
78
|
+
outputBytes += chunk.length;
|
|
79
|
+
if (outputBytes <= maxOutputBytes) {
|
|
80
|
+
stderr += chunk.toString();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
child.on('close', (code) => {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
if (abortSignal) {
|
|
86
|
+
abortSignal.removeEventListener('abort', onAbort);
|
|
87
|
+
}
|
|
88
|
+
const durationMs = Date.now() - startTime;
|
|
89
|
+
if (killed && outputBytes > maxOutputBytes) {
|
|
90
|
+
resolve({
|
|
91
|
+
requestId,
|
|
92
|
+
status: 'failed',
|
|
93
|
+
stdout: stdout.slice(0, maxOutputBytes),
|
|
94
|
+
stderr,
|
|
95
|
+
durationMs,
|
|
96
|
+
error: `Output exceeded ${maxOutputBytes} bytes limit`,
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (killed) {
|
|
101
|
+
resolve({
|
|
102
|
+
requestId,
|
|
103
|
+
status: 'timed_out',
|
|
104
|
+
stdout,
|
|
105
|
+
stderr,
|
|
106
|
+
durationMs,
|
|
107
|
+
error: `Command timed out after ${timeoutMs}ms`,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
resolve({
|
|
112
|
+
requestId,
|
|
113
|
+
status: code === 0 ? 'completed' : 'failed',
|
|
114
|
+
exitCode: code ?? undefined,
|
|
115
|
+
stdout,
|
|
116
|
+
stderr,
|
|
117
|
+
durationMs,
|
|
118
|
+
});
|
|
119
|
+
log.info({ requestId, exitCode: code, durationMs }, 'Command completed');
|
|
120
|
+
});
|
|
121
|
+
child.on('error', (err) => {
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
if (abortSignal) {
|
|
124
|
+
abortSignal.removeEventListener('abort', onAbort);
|
|
125
|
+
}
|
|
126
|
+
resolve({
|
|
127
|
+
requestId,
|
|
128
|
+
status: 'failed',
|
|
129
|
+
error: `Failed to execute: ${err.message}`,
|
|
130
|
+
durationMs: Date.now() - startTime,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
activeExecutions--;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=execute_command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute_command.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/execute_command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Telegraf, Markup } from 'telegraf';
|
|
2
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
3
|
+
const log = createChildLogger('telegram');
|
|
4
|
+
export function createTelegramApprovalChannel(token, chatId, pendingStore, approvalStore, auditLog) {
|
|
5
|
+
const bot = new Telegraf(token);
|
|
6
|
+
bot.on('callback_query', async (ctx) => {
|
|
7
|
+
const data = 'data' in ctx.callbackQuery ? ctx.callbackQuery.data : undefined;
|
|
8
|
+
if (!data)
|
|
9
|
+
return;
|
|
10
|
+
// Validate chat ID to prevent unauthorized approvals
|
|
11
|
+
const callbackChatId = ctx.callbackQuery.message?.chat?.id?.toString();
|
|
12
|
+
if (callbackChatId !== chatId) {
|
|
13
|
+
log.warn({ callbackChatId, expectedChatId: chatId }, 'Callback from unauthorized chat');
|
|
14
|
+
await ctx.answerCbQuery('Unauthorized');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Parse callback data: "action:requestId:matchType:duration"
|
|
18
|
+
const parts = data.split(':');
|
|
19
|
+
if (parts.length !== 4)
|
|
20
|
+
return;
|
|
21
|
+
const [action, requestId, matchType, duration] = parts;
|
|
22
|
+
const pending = pendingStore.get(requestId);
|
|
23
|
+
if (!pending) {
|
|
24
|
+
await ctx.answerCbQuery('Request expired or already decided');
|
|
25
|
+
await ctx.editMessageReplyMarkup(undefined);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const decision = action === 'approve' ? 'approved' : 'denied';
|
|
29
|
+
if (decision === 'approved') {
|
|
30
|
+
const approvalCommand = matchType === 'prefix'
|
|
31
|
+
? pending.command.split(/\s+/).slice(0, 2).join(' ')
|
|
32
|
+
: pending.command;
|
|
33
|
+
approvalStore.addApproval(approvalCommand, matchType, duration, `telegram:${ctx.callbackQuery.from.id}`);
|
|
34
|
+
}
|
|
35
|
+
auditLog.append({
|
|
36
|
+
ts: new Date().toISOString(),
|
|
37
|
+
type: decision === 'approved' ? 'approved' : 'denied',
|
|
38
|
+
requestId,
|
|
39
|
+
command: pending.command,
|
|
40
|
+
duration: decision === 'approved' ? duration : undefined,
|
|
41
|
+
approvedBy: `telegram:${ctx.callbackQuery.from.id}`,
|
|
42
|
+
});
|
|
43
|
+
pendingStore.resolve(requestId, decision);
|
|
44
|
+
const emoji = decision === 'approved' ? '\u2705' : '\u274c';
|
|
45
|
+
const label = decision === 'approved' ? `Approved (${matchType} ${duration}h)` : 'Denied';
|
|
46
|
+
await ctx.answerCbQuery(label);
|
|
47
|
+
await ctx.editMessageText(`${emoji} ${label}\n\n${pending.command}`);
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
async requestApproval(command, apiKeyName, ip, requestId, riskAnalysis) {
|
|
51
|
+
let text = `\u{1f6a8} **Command Request**\n\n`;
|
|
52
|
+
text += `From: \`${apiKeyName}\` (${ip})\n`;
|
|
53
|
+
text += `ID: \`${requestId}\`\n\n`;
|
|
54
|
+
text += `\`\`\`\n${command}\n\`\`\``;
|
|
55
|
+
if (riskAnalysis.warnings.length > 0) {
|
|
56
|
+
const icon = riskAnalysis.level === 'danger' ? '\u{26a0}\ufe0f DANGER' : '\u{26a0}\ufe0f WARNING';
|
|
57
|
+
text += `\n\n${icon}:\n`;
|
|
58
|
+
text += riskAnalysis.warnings.map(w => `• ${w}`).join('\n');
|
|
59
|
+
}
|
|
60
|
+
const prefix = command.split(/\s+/).slice(0, 2).join(' ');
|
|
61
|
+
const keyboard = Markup.inlineKeyboard([
|
|
62
|
+
[
|
|
63
|
+
Markup.button.callback('Exact 2h', `approve:${requestId}:exact:2`),
|
|
64
|
+
Markup.button.callback('Exact 8h', `approve:${requestId}:exact:8`),
|
|
65
|
+
Markup.button.callback('Exact \u221e', `approve:${requestId}:exact:permanent`),
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
Markup.button.callback(`"${prefix}" 2h`, `approve:${requestId}:prefix:2`),
|
|
69
|
+
Markup.button.callback(`"${prefix}" 8h`, `approve:${requestId}:prefix:8`),
|
|
70
|
+
],
|
|
71
|
+
[
|
|
72
|
+
Markup.button.callback('\u274c Deny', `deny:${requestId}:exact:0`),
|
|
73
|
+
],
|
|
74
|
+
]);
|
|
75
|
+
await bot.telegram.sendMessage(chatId, text, {
|
|
76
|
+
parse_mode: 'Markdown',
|
|
77
|
+
...keyboard,
|
|
78
|
+
});
|
|
79
|
+
auditLog.append({
|
|
80
|
+
ts: new Date().toISOString(),
|
|
81
|
+
type: 'telegram_sent',
|
|
82
|
+
requestId,
|
|
83
|
+
command,
|
|
84
|
+
apiKeyName,
|
|
85
|
+
ip,
|
|
86
|
+
});
|
|
87
|
+
log.info({ requestId, command, chatId }, 'Telegram approval request sent');
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const pending = pendingStore.get(requestId);
|
|
90
|
+
if (!pending) {
|
|
91
|
+
reject(new Error('Request not found in pending store'));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const originalResolve = pending.resolve;
|
|
95
|
+
const originalReject = pending.reject;
|
|
96
|
+
pending.resolve = (decision) => {
|
|
97
|
+
const matchType = 'exact';
|
|
98
|
+
const duration = 'unknown';
|
|
99
|
+
originalResolve(decision);
|
|
100
|
+
resolve({ decision, matchType, duration });
|
|
101
|
+
};
|
|
102
|
+
pending.reject = (reason) => {
|
|
103
|
+
originalReject(reason);
|
|
104
|
+
reject(reason);
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
async start() {
|
|
109
|
+
await bot.launch();
|
|
110
|
+
log.info('Telegram bot started');
|
|
111
|
+
// Startup health check
|
|
112
|
+
try {
|
|
113
|
+
await bot.telegram.sendMessage(chatId, '\u{1f7e2} Lucifer started. Approval channel active.');
|
|
114
|
+
log.info({ chatId }, 'Telegram health check passed');
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
log.error({ chatId, err }, 'Failed to send startup message. Check LUCIFER_TELEGRAM_CHAT_ID.');
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
async stop() {
|
|
121
|
+
bot.stop('Shutdown');
|
|
122
|
+
log.info('Telegram bot stopped');
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=request_telegram_approval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request_telegram_approval.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/request_telegram_approval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command_types.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/types/command_types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store_interfaces.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/types/store_interfaces.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register_health_routes.js","sourceRoot":"","sources":["../../../../../server/src/domains/platform-api/api/register_health_routes.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,oBAAoB,CAClC,GAAY,EACZ,eAAoC;IAEpC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,QAAiB,EAAE,QAAkB,EAAE,EAAE;QAC/D,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
function parsePort(value) {
|
|
3
|
+
const parsedPort = Number.parseInt(value ?? '3001', 10);
|
|
4
|
+
if (Number.isInteger(parsedPort) && parsedPort >= 1 && parsedPort <= 65535) {
|
|
5
|
+
return parsedPort;
|
|
6
|
+
}
|
|
7
|
+
return 3001;
|
|
8
|
+
}
|
|
9
|
+
export function getServerConfig() {
|
|
10
|
+
return {
|
|
11
|
+
appName: 'lucifer',
|
|
12
|
+
clientDistPath: path.resolve(process.cwd(), 'dist/client'),
|
|
13
|
+
environment: process.env.NODE_ENV ?? 'development',
|
|
14
|
+
port: parsePort(process.env.PORT),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=server_config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server_config.js","sourceRoot":"","sources":["../../../../../server/src/domains/platform-api/config/server_config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAS5B,SAAS,SAAS,CAAC,KAAyB;IAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;IAEvD,IAAI,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QAC3E,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC;QAC1D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;QAClD,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;KAClC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime_metadata_repository.js","sourceRoot":"","sources":["../../../../../server/src/domains/platform-api/repository/runtime_metadata_repository.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,+BAA+B;IAC7C,OAAO;QACL,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnD,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO;KACtC,CAAA;AACH,CAAC"}
|