shieldcortex 2.17.1 → 2.19.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/README.md +42 -24
- package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_25b1b286._.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/1a71c9a52f0c9b16.css +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/6bf7d89d34068ecb.js +9 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/d0dcb5e0e04ae015.js +1 -0
- package/dashboard/.next/standalone/dashboard/package.json +1 -1
- package/dist/api/visualization-server.d.ts.map +1 -1
- package/dist/api/visualization-server.js +306 -0
- package/dist/api/visualization-server.js.map +1 -1
- package/dist/cloud/config.d.ts +13 -1
- package/dist/cloud/config.d.ts.map +1 -1
- package/dist/cloud/config.js +28 -3
- package/dist/cloud/config.js.map +1 -1
- package/dist/database/init.d.ts.map +1 -1
- package/dist/database/init.js +77 -0
- package/dist/database/init.js.map +1 -1
- package/dist/defence/__tests__/tool-response-scanner.test.d.ts +8 -0
- package/dist/defence/__tests__/tool-response-scanner.test.d.ts.map +1 -0
- package/dist/defence/__tests__/tool-response-scanner.test.js +106 -0
- package/dist/defence/__tests__/tool-response-scanner.test.js.map +1 -0
- package/dist/defence/audit/export.d.ts +6 -0
- package/dist/defence/audit/export.d.ts.map +1 -0
- package/dist/defence/audit/export.js +43 -0
- package/dist/defence/audit/export.js.map +1 -0
- package/dist/defence/custom-patterns/store.d.ts +52 -0
- package/dist/defence/custom-patterns/store.d.ts.map +1 -0
- package/dist/defence/custom-patterns/store.js +108 -0
- package/dist/defence/custom-patterns/store.js.map +1 -0
- package/dist/defence/custom-rules/store.d.ts +36 -0
- package/dist/defence/custom-rules/store.d.ts.map +1 -0
- package/dist/defence/custom-rules/store.js +57 -0
- package/dist/defence/custom-rules/store.js.map +1 -0
- package/dist/defence/iron-dome/custom-policies.d.ts +31 -0
- package/dist/defence/iron-dome/custom-policies.d.ts.map +1 -0
- package/dist/defence/iron-dome/custom-policies.js +79 -0
- package/dist/defence/iron-dome/custom-policies.js.map +1 -0
- package/dist/defence/iron-dome/index.d.ts +5 -5
- package/dist/defence/iron-dome/index.d.ts.map +1 -1
- package/dist/defence/iron-dome/index.js +55 -6
- package/dist/defence/iron-dome/index.js.map +1 -1
- package/dist/defence/pipeline.d.ts.map +1 -1
- package/dist/defence/pipeline.js +82 -6
- package/dist/defence/pipeline.js.map +1 -1
- package/dist/defence/skill-scanner/deep-scan.d.ts +30 -0
- package/dist/defence/skill-scanner/deep-scan.d.ts.map +1 -0
- package/dist/defence/skill-scanner/deep-scan.js +112 -0
- package/dist/defence/skill-scanner/deep-scan.js.map +1 -0
- package/dist/defence/tool-response-scanner.d.ts +23 -0
- package/dist/defence/tool-response-scanner.d.ts.map +1 -0
- package/dist/defence/tool-response-scanner.js +157 -0
- package/dist/defence/tool-response-scanner.js.map +1 -0
- package/dist/defence/trust/source-scorer.d.ts.map +1 -1
- package/dist/defence/trust/source-scorer.js +2 -1
- package/dist/defence/trust/source-scorer.js.map +1 -1
- package/dist/defence/types.d.ts +13 -2
- package/dist/defence/types.d.ts.map +1 -1
- package/dist/defence/types.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +4 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +4 -0
- package/dist/lib.js.map +1 -1
- package/dist/license/__tests__/feature-gating.test.d.ts +10 -0
- package/dist/license/__tests__/feature-gating.test.d.ts.map +1 -0
- package/dist/license/__tests__/feature-gating.test.js +188 -0
- package/dist/license/__tests__/feature-gating.test.js.map +1 -0
- package/dist/license/cli.d.ts +9 -0
- package/dist/license/cli.d.ts.map +1 -0
- package/dist/license/cli.js +141 -0
- package/dist/license/cli.js.map +1 -0
- package/dist/license/gate.d.ts +38 -0
- package/dist/license/gate.d.ts.map +1 -0
- package/dist/license/gate.js +84 -0
- package/dist/license/gate.js.map +1 -0
- package/dist/license/index.d.ts +13 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +12 -0
- package/dist/license/index.js.map +1 -0
- package/dist/license/keys.d.ts +50 -0
- package/dist/license/keys.d.ts.map +1 -0
- package/dist/license/keys.js +30 -0
- package/dist/license/keys.js.map +1 -0
- package/dist/license/store.d.ts +45 -0
- package/dist/license/store.d.ts.map +1 -0
- package/dist/license/store.js +148 -0
- package/dist/license/store.js.map +1 -0
- package/dist/license/types.d.ts +16 -0
- package/dist/license/types.d.ts.map +1 -0
- package/dist/license/types.js +6 -0
- package/dist/license/types.js.map +1 -0
- package/dist/license/validate.d.ts +24 -0
- package/dist/license/validate.d.ts.map +1 -0
- package/dist/license/validate.js +86 -0
- package/dist/license/validate.js.map +1 -0
- package/dist/license/verify.d.ts +18 -0
- package/dist/license/verify.d.ts.map +1 -0
- package/dist/license/verify.js +126 -0
- package/dist/license/verify.js.map +1 -0
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +18 -16
- package/dist/memory/store.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +99 -16
- package/dist/server.js.map +1 -1
- package/dist/tools/context.d.ts +5 -5
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +3 -1
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/forget.d.ts +5 -5
- package/dist/tools/forget.js +1 -1
- package/dist/tools/forget.js.map +1 -1
- package/dist/tools/recall.d.ts +10 -10
- package/dist/tools/recall.js +1 -1
- package/dist/tools/recall.js.map +1 -1
- package/dist/tools/remember.d.ts +7 -7
- package/dist/tools/remember.js +1 -1
- package/dist/tools/remember.js.map +1 -1
- package/dist/worker/brain-worker.d.ts.map +1 -1
- package/dist/worker/brain-worker.js +25 -18
- package/dist/worker/brain-worker.js.map +1 -1
- package/hooks/openclaw/cortex-memory/HOOK.md +7 -7
- package/hooks/openclaw/cortex-memory/handler.ts +1 -1
- package/package.json +2 -1
- package/plugins/openclaw/README.md +8 -8
- package/plugins/openclaw/index.ts +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/42d01b77019fd208.js +0 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/61a3c89b08347bc2.js +0 -9
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/c252c4de65df6d09.css +0 -3
- /package/dashboard/.next/standalone/dashboard/.next/static/{H-BGC5Yp6YmPEZGryV6bd → OfvwyqIJFP9N3Qdb23S-6}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{H-BGC5Yp6YmPEZGryV6bd → OfvwyqIJFP9N3Qdb23S-6}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{H-BGC5Yp6YmPEZGryV6bd → OfvwyqIJFP9N3Qdb23S-6}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License file I/O — reads/writes ~/.shieldcortex/license.json
|
|
3
|
+
*
|
|
4
|
+
* The Ed25519 signature on the key itself provides integrity for the tier
|
|
5
|
+
* and expiry. The validationStatus field is advisory — a tampered value
|
|
6
|
+
* only persists until the next online validation (≤24h). HMAC is not
|
|
7
|
+
* needed here because the hard security boundary is the signed key, not
|
|
8
|
+
* the JSON file.
|
|
9
|
+
*
|
|
10
|
+
* License is cached in memory after first read.
|
|
11
|
+
*/
|
|
12
|
+
import type { LicenseTier, LicenseInfo, LicenseFile } from './keys.js';
|
|
13
|
+
/** Clear the in-memory cache (useful for testing or after activation). */
|
|
14
|
+
export declare function clearLicenseCache(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Read and verify the stored license.
|
|
17
|
+
* Returns a LicenseInfo with tier='free' if no license exists or verification fails.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getLicense(): LicenseInfo;
|
|
20
|
+
/**
|
|
21
|
+
* Quick accessor for the current licence tier.
|
|
22
|
+
* Returns 'free' if no valid licence exists.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getLicenseTier(): LicenseTier;
|
|
25
|
+
/**
|
|
26
|
+
* Read the raw license file data (for status display).
|
|
27
|
+
* Returns null if no license file exists.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getLicenseFile(): LicenseFile | null;
|
|
30
|
+
/**
|
|
31
|
+
* Activate a license key — verify it, then store in license.json.
|
|
32
|
+
* Returns the verified LicenseInfo.
|
|
33
|
+
* Throws if the key is invalid.
|
|
34
|
+
*/
|
|
35
|
+
export declare function activateLicense(key: string): LicenseInfo;
|
|
36
|
+
/**
|
|
37
|
+
* Remove the license file (deactivate).
|
|
38
|
+
*/
|
|
39
|
+
export declare function deactivateLicense(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Update the validation status and timestamp in the license file.
|
|
42
|
+
* Called by the online validation module.
|
|
43
|
+
*/
|
|
44
|
+
export declare function updateValidationStatus(status: LicenseFile['validationStatus']): void;
|
|
45
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/license/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AASvE,0EAA0E;AAC1E,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAID;;;GAGG;AACH,wBAAgB,UAAU,IAAI,WAAW,CA0CxC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAOnD;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAmBxD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CASxC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAepF"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License file I/O — reads/writes ~/.shieldcortex/license.json
|
|
3
|
+
*
|
|
4
|
+
* The Ed25519 signature on the key itself provides integrity for the tier
|
|
5
|
+
* and expiry. The validationStatus field is advisory — a tampered value
|
|
6
|
+
* only persists until the next online validation (≤24h). HMAC is not
|
|
7
|
+
* needed here because the hard security boundary is the signed key, not
|
|
8
|
+
* the JSON file.
|
|
9
|
+
*
|
|
10
|
+
* License is cached in memory after first read.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { homedir } from 'os';
|
|
15
|
+
import { verifyLicenseKey } from './verify.js';
|
|
16
|
+
const CONFIG_DIR = join(homedir(), '.shieldcortex');
|
|
17
|
+
const LICENSE_FILE = join(CONFIG_DIR, 'license.json');
|
|
18
|
+
// ── Cache ────────────────────────────────────────────────
|
|
19
|
+
let cachedLicense = null;
|
|
20
|
+
/** Clear the in-memory cache (useful for testing or after activation). */
|
|
21
|
+
export function clearLicenseCache() {
|
|
22
|
+
cachedLicense = null;
|
|
23
|
+
}
|
|
24
|
+
// ── Read ─────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Read and verify the stored license.
|
|
27
|
+
* Returns a LicenseInfo with tier='free' if no license exists or verification fails.
|
|
28
|
+
*/
|
|
29
|
+
export function getLicense() {
|
|
30
|
+
if (cachedLicense)
|
|
31
|
+
return cachedLicense;
|
|
32
|
+
const FREE = {
|
|
33
|
+
valid: false,
|
|
34
|
+
tier: 'free',
|
|
35
|
+
email: null,
|
|
36
|
+
expiresAt: null,
|
|
37
|
+
daysUntilExpiry: null,
|
|
38
|
+
teamId: null,
|
|
39
|
+
subscriptionId: null,
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
if (!existsSync(LICENSE_FILE)) {
|
|
43
|
+
cachedLicense = FREE;
|
|
44
|
+
return FREE;
|
|
45
|
+
}
|
|
46
|
+
const raw = JSON.parse(readFileSync(LICENSE_FILE, 'utf-8'));
|
|
47
|
+
if (!raw.key) {
|
|
48
|
+
cachedLicense = FREE;
|
|
49
|
+
return FREE;
|
|
50
|
+
}
|
|
51
|
+
// Check if previously marked as revoked or expired by online validation.
|
|
52
|
+
// Revoked = subscription cancelled (hard block).
|
|
53
|
+
// Expired = advisory; verifyLicenseKey() applies the 7-day grace period
|
|
54
|
+
// so we only hard-block on revoked here.
|
|
55
|
+
if (raw.validationStatus === 'revoked') {
|
|
56
|
+
cachedLicense = FREE;
|
|
57
|
+
return FREE;
|
|
58
|
+
}
|
|
59
|
+
// Verify the key cryptographically (checks exp + grace period)
|
|
60
|
+
const info = verifyLicenseKey(raw.key);
|
|
61
|
+
cachedLicense = info;
|
|
62
|
+
return info;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
cachedLicense = FREE;
|
|
66
|
+
return FREE;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Quick accessor for the current licence tier.
|
|
71
|
+
* Returns 'free' if no valid licence exists.
|
|
72
|
+
*/
|
|
73
|
+
export function getLicenseTier() {
|
|
74
|
+
return getLicense().tier;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Read the raw license file data (for status display).
|
|
78
|
+
* Returns null if no license file exists.
|
|
79
|
+
*/
|
|
80
|
+
export function getLicenseFile() {
|
|
81
|
+
try {
|
|
82
|
+
if (!existsSync(LICENSE_FILE))
|
|
83
|
+
return null;
|
|
84
|
+
return JSON.parse(readFileSync(LICENSE_FILE, 'utf-8'));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ── Write ────────────────────────────────────────────────
|
|
91
|
+
/**
|
|
92
|
+
* Activate a license key — verify it, then store in license.json.
|
|
93
|
+
* Returns the verified LicenseInfo.
|
|
94
|
+
* Throws if the key is invalid.
|
|
95
|
+
*/
|
|
96
|
+
export function activateLicense(key) {
|
|
97
|
+
const info = verifyLicenseKey(key);
|
|
98
|
+
if (!info.valid) {
|
|
99
|
+
throw new Error('Invalid or expired licence key. Check the key and try again.');
|
|
100
|
+
}
|
|
101
|
+
const file = {
|
|
102
|
+
key,
|
|
103
|
+
activatedAt: new Date().toISOString(),
|
|
104
|
+
lastValidatedAt: null,
|
|
105
|
+
validationStatus: 'unvalidated',
|
|
106
|
+
};
|
|
107
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
108
|
+
writeFileSync(LICENSE_FILE, JSON.stringify(file, null, 2) + '\n', { mode: 0o600 });
|
|
109
|
+
// Invalidate cache
|
|
110
|
+
cachedLicense = info;
|
|
111
|
+
return info;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Remove the license file (deactivate).
|
|
115
|
+
*/
|
|
116
|
+
export function deactivateLicense() {
|
|
117
|
+
try {
|
|
118
|
+
if (existsSync(LICENSE_FILE)) {
|
|
119
|
+
unlinkSync(LICENSE_FILE);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Best effort
|
|
124
|
+
}
|
|
125
|
+
cachedLicense = null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Update the validation status and timestamp in the license file.
|
|
129
|
+
* Called by the online validation module.
|
|
130
|
+
*/
|
|
131
|
+
export function updateValidationStatus(status) {
|
|
132
|
+
try {
|
|
133
|
+
if (!existsSync(LICENSE_FILE))
|
|
134
|
+
return;
|
|
135
|
+
const raw = JSON.parse(readFileSync(LICENSE_FILE, 'utf-8'));
|
|
136
|
+
raw.validationStatus = status;
|
|
137
|
+
raw.lastValidatedAt = new Date().toISOString();
|
|
138
|
+
writeFileSync(LICENSE_FILE, JSON.stringify(raw, null, 2) + '\n', { mode: 0o600 });
|
|
139
|
+
// If revoked or expired, invalidate cache so next getLicense() re-verifies
|
|
140
|
+
if (status === 'revoked' || status === 'expired') {
|
|
141
|
+
cachedLicense = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Best effort
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/license/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AACpD,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AAEtD,4DAA4D;AAE5D,IAAI,aAAa,GAAuB,IAAI,CAAC;AAE7C,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,4DAA4D;AAE5D;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,IAAI,GAAgB;QACxB,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;QACf,eAAe,EAAE,IAAI;QACrB,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,IAAI;KACrB,CAAC;IAEF,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,aAAa,GAAG,IAAI,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,GAAG,GAAgB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;YACb,aAAa,GAAG,IAAI,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yEAAyE;QACzE,iDAAiD;QACjD,wEAAwE;QACxE,yCAAyC;QACzC,IAAI,GAAG,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACvC,aAAa,GAAG,IAAI,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,+DAA+D;QAC/D,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,aAAa,GAAG,IAAI,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,IAAI,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,EAAE,CAAC,IAAI,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,4DAA4D;AAE5D;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,IAAI,GAAgB;QACxB,GAAG;QACH,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,aAAa;KAChC,CAAC;IAEF,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEnF,mBAAmB;IACnB,aAAa,GAAG,IAAI,CAAC;IACrB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,UAAU,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAuC;IAC5E,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO;QACtC,MAAM,GAAG,GAAgB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QACzE,GAAG,CAAC,gBAAgB,GAAG,MAAM,CAAC;QAC9B,GAAG,CAAC,eAAe,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC/C,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAElF,2EAA2E;QAC3E,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACjD,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the license feature gating system.
|
|
3
|
+
* Used by both the backend (visualization-server) and frontend (dashboard).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Structured 403 response returned when a gated feature is accessed
|
|
7
|
+
* without the required licence tier.
|
|
8
|
+
*/
|
|
9
|
+
export interface FeatureGatedResponse {
|
|
10
|
+
error: string;
|
|
11
|
+
code: 'FEATURE_GATED';
|
|
12
|
+
feature: string;
|
|
13
|
+
requiredTier: string;
|
|
14
|
+
upgradeUrl: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/license/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/license/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Periodic online licence validation — catches revocations.
|
|
3
|
+
*
|
|
4
|
+
* Fire-and-forget, never blocks. Same pattern as syncToCloud() in cloud/sync.ts.
|
|
5
|
+
* If offline, the licence stays valid until its exp date.
|
|
6
|
+
*/
|
|
7
|
+
type ValidationStatus = 'valid' | 'revoked' | 'expired';
|
|
8
|
+
/**
|
|
9
|
+
* Run online validation if enough time has passed since the last check.
|
|
10
|
+
* Non-blocking — errors are silently ignored.
|
|
11
|
+
*/
|
|
12
|
+
export declare function scheduleOnlineValidation(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Validate the stored licence key against the SaaS API.
|
|
15
|
+
* Called periodically (every 24h) and once on activation.
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateOnline(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Run a one-time validation immediately (used during activation).
|
|
20
|
+
* Returns the validation status, or 'unvalidated' if the check fails.
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateOnceNow(): Promise<ValidationStatus | 'unvalidated'>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/license/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,KAAK,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAIxD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAO/C;AAmCD;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAYpD;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,gBAAgB,GAAG,aAAa,CAAC,CAajF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Periodic online licence validation — catches revocations.
|
|
3
|
+
*
|
|
4
|
+
* Fire-and-forget, never blocks. Same pattern as syncToCloud() in cloud/sync.ts.
|
|
5
|
+
* If offline, the licence stays valid until its exp date.
|
|
6
|
+
*/
|
|
7
|
+
import { getLicenseFile, updateValidationStatus } from './store.js';
|
|
8
|
+
import { parseLicensePayload } from './verify.js';
|
|
9
|
+
import { ONLINE_VALIDATION_INTERVAL_MS } from './keys.js';
|
|
10
|
+
import { getCloudConfig } from '../cloud/config.js';
|
|
11
|
+
let lastValidationAttempt = 0;
|
|
12
|
+
/**
|
|
13
|
+
* Run online validation if enough time has passed since the last check.
|
|
14
|
+
* Non-blocking — errors are silently ignored.
|
|
15
|
+
*/
|
|
16
|
+
export function scheduleOnlineValidation() {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
if (now - lastValidationAttempt < ONLINE_VALIDATION_INTERVAL_MS)
|
|
19
|
+
return;
|
|
20
|
+
lastValidationAttempt = now;
|
|
21
|
+
// Fire-and-forget
|
|
22
|
+
validateOnline().catch(() => { });
|
|
23
|
+
}
|
|
24
|
+
// ── Shared HTTP helper ──────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Fetch the validation status from the SaaS API.
|
|
27
|
+
* Returns null on network error, timeout, or server error.
|
|
28
|
+
*/
|
|
29
|
+
async function fetchValidationStatus(sid) {
|
|
30
|
+
const config = getCloudConfig();
|
|
31
|
+
const baseUrl = config.cloudBaseUrl || 'https://api.shieldcortex.ai';
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(`${baseUrl}/v1/license/validate?sid=${encodeURIComponent(sid)}`, { signal: controller.signal });
|
|
36
|
+
if (!res.ok)
|
|
37
|
+
return null;
|
|
38
|
+
const data = await res.json();
|
|
39
|
+
if (data.status === 'unknown')
|
|
40
|
+
return null; // Subscription not found — treat as network error
|
|
41
|
+
return data.status === 'active' ? 'valid' : data.status;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
clearTimeout(timeout);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ── Public API ──────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Validate the stored licence key against the SaaS API.
|
|
53
|
+
* Called periodically (every 24h) and once on activation.
|
|
54
|
+
*/
|
|
55
|
+
export async function validateOnline() {
|
|
56
|
+
const file = getLicenseFile();
|
|
57
|
+
if (!file?.key)
|
|
58
|
+
return;
|
|
59
|
+
const payload = parseLicensePayload(file.key);
|
|
60
|
+
if (!payload?.sid)
|
|
61
|
+
return;
|
|
62
|
+
const status = await fetchValidationStatus(payload.sid);
|
|
63
|
+
if (status) {
|
|
64
|
+
updateValidationStatus(status);
|
|
65
|
+
}
|
|
66
|
+
// If null (network error), leave status unchanged — licence stays valid
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Run a one-time validation immediately (used during activation).
|
|
70
|
+
* Returns the validation status, or 'unvalidated' if the check fails.
|
|
71
|
+
*/
|
|
72
|
+
export async function validateOnceNow() {
|
|
73
|
+
const file = getLicenseFile();
|
|
74
|
+
if (!file?.key)
|
|
75
|
+
return 'unvalidated';
|
|
76
|
+
const payload = parseLicensePayload(file.key);
|
|
77
|
+
if (!payload?.sid)
|
|
78
|
+
return 'unvalidated';
|
|
79
|
+
const status = await fetchValidationStatus(payload.sid);
|
|
80
|
+
if (status) {
|
|
81
|
+
updateValidationStatus(status);
|
|
82
|
+
return status;
|
|
83
|
+
}
|
|
84
|
+
return 'unvalidated';
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/license/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline Ed25519 licence key verification.
|
|
3
|
+
*
|
|
4
|
+
* Uses Node.js built-in crypto (available since Node 18).
|
|
5
|
+
* Zero external dependencies.
|
|
6
|
+
*/
|
|
7
|
+
import { type LicensePayload, type LicenseInfo } from './keys.js';
|
|
8
|
+
/**
|
|
9
|
+
* Parse the payload JSON from a license key without verifying the signature.
|
|
10
|
+
* Returns null if parsing fails.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseLicensePayload(key: string): LicensePayload | null;
|
|
13
|
+
/**
|
|
14
|
+
* Verify a license key's Ed25519 signature and check expiry.
|
|
15
|
+
* This is completely offline — no network calls.
|
|
16
|
+
*/
|
|
17
|
+
export declare function verifyLicenseKey(key: string): LicenseInfo;
|
|
18
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/license/verify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,WAAW,CAAC;AA4CnB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAiBtE;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAuDzD"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline Ed25519 licence key verification.
|
|
3
|
+
*
|
|
4
|
+
* Uses Node.js built-in crypto (available since Node 18).
|
|
5
|
+
* Zero external dependencies.
|
|
6
|
+
*/
|
|
7
|
+
import { verify, createPublicKey } from 'crypto';
|
|
8
|
+
import { LICENSE_PUBLIC_KEY_HEX, KEY_PREFIXES, EXPIRY_GRACE_DAYS, } from './keys.js';
|
|
9
|
+
// ── Base64url helpers ────────────────────────────────────
|
|
10
|
+
function base64urlDecode(str) {
|
|
11
|
+
// Restore padding and convert base64url → base64
|
|
12
|
+
const padded = str + '='.repeat((4 - (str.length % 4)) % 4);
|
|
13
|
+
return Buffer.from(padded.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
|
|
14
|
+
}
|
|
15
|
+
// ── Public key (parsed once, cached) ─────────────────────
|
|
16
|
+
let cachedPublicKey = null;
|
|
17
|
+
function getPublicKey() {
|
|
18
|
+
if (cachedPublicKey)
|
|
19
|
+
return cachedPublicKey;
|
|
20
|
+
const derBuffer = Buffer.from(LICENSE_PUBLIC_KEY_HEX, 'hex');
|
|
21
|
+
cachedPublicKey = createPublicKey({ key: derBuffer, format: 'der', type: 'spki' });
|
|
22
|
+
return cachedPublicKey;
|
|
23
|
+
}
|
|
24
|
+
// ── Key parsing ──────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Strip the sc_{tier}_ prefix and split into payload + signature.
|
|
27
|
+
* Returns null if the key format is invalid.
|
|
28
|
+
*/
|
|
29
|
+
function splitKey(key) {
|
|
30
|
+
// Find which prefix matches
|
|
31
|
+
for (const [tier, prefix] of Object.entries(KEY_PREFIXES)) {
|
|
32
|
+
if (key.startsWith(prefix)) {
|
|
33
|
+
const rest = key.slice(prefix.length);
|
|
34
|
+
const dotIndex = rest.lastIndexOf('.');
|
|
35
|
+
if (dotIndex === -1)
|
|
36
|
+
return null;
|
|
37
|
+
return {
|
|
38
|
+
payloadB64: rest.slice(0, dotIndex),
|
|
39
|
+
signatureB64: rest.slice(dotIndex + 1),
|
|
40
|
+
prefixTier: tier,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse the payload JSON from a license key without verifying the signature.
|
|
48
|
+
* Returns null if parsing fails.
|
|
49
|
+
*/
|
|
50
|
+
export function parseLicensePayload(key) {
|
|
51
|
+
const parts = splitKey(key);
|
|
52
|
+
if (!parts)
|
|
53
|
+
return null;
|
|
54
|
+
try {
|
|
55
|
+
const json = base64urlDecode(parts.payloadB64).toString('utf-8');
|
|
56
|
+
const payload = JSON.parse(json);
|
|
57
|
+
// Basic shape validation
|
|
58
|
+
if (!payload.tier || !payload.teamId || !payload.exp || !payload.sid) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return payload;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ── Signature verification ───────────────────────────────
|
|
68
|
+
/**
|
|
69
|
+
* Verify a license key's Ed25519 signature and check expiry.
|
|
70
|
+
* This is completely offline — no network calls.
|
|
71
|
+
*/
|
|
72
|
+
export function verifyLicenseKey(key) {
|
|
73
|
+
const FREE = {
|
|
74
|
+
valid: false,
|
|
75
|
+
tier: 'free',
|
|
76
|
+
email: null,
|
|
77
|
+
expiresAt: null,
|
|
78
|
+
daysUntilExpiry: null,
|
|
79
|
+
teamId: null,
|
|
80
|
+
subscriptionId: null,
|
|
81
|
+
};
|
|
82
|
+
const parts = splitKey(key);
|
|
83
|
+
if (!parts)
|
|
84
|
+
return FREE;
|
|
85
|
+
// Decode payload and signature
|
|
86
|
+
let payload;
|
|
87
|
+
let signatureBuffer;
|
|
88
|
+
try {
|
|
89
|
+
const json = base64urlDecode(parts.payloadB64).toString('utf-8');
|
|
90
|
+
payload = JSON.parse(json);
|
|
91
|
+
signatureBuffer = base64urlDecode(parts.signatureB64);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return FREE;
|
|
95
|
+
}
|
|
96
|
+
// Verify Ed25519 signature over the raw payload bytes
|
|
97
|
+
const payloadBuffer = base64urlDecode(parts.payloadB64);
|
|
98
|
+
try {
|
|
99
|
+
const isValid = verify(null, payloadBuffer, getPublicKey(), signatureBuffer);
|
|
100
|
+
if (!isValid)
|
|
101
|
+
return FREE;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return FREE;
|
|
105
|
+
}
|
|
106
|
+
// Check that the prefix tier matches the payload tier
|
|
107
|
+
if (parts.prefixTier !== payload.tier)
|
|
108
|
+
return FREE;
|
|
109
|
+
// Check expiry (with grace period)
|
|
110
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
111
|
+
const graceSeconds = EXPIRY_GRACE_DAYS * 24 * 60 * 60;
|
|
112
|
+
const effectiveExpiry = payload.exp + graceSeconds;
|
|
113
|
+
const expired = nowSec > effectiveExpiry;
|
|
114
|
+
const expiresAt = new Date(payload.exp * 1000);
|
|
115
|
+
const daysUntilExpiry = Math.ceil((payload.exp - nowSec) / (24 * 60 * 60));
|
|
116
|
+
return {
|
|
117
|
+
valid: !expired,
|
|
118
|
+
tier: expired ? 'free' : payload.tier,
|
|
119
|
+
email: payload.email,
|
|
120
|
+
expiresAt,
|
|
121
|
+
daysUntilExpiry,
|
|
122
|
+
teamId: payload.teamId,
|
|
123
|
+
subscriptionId: payload.sid,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/license/verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,MAAM,EACN,WAAW,EACX,UAAU,EAEV,aAAa,EACb,YAAY,EACZ,YAAY,EAEb,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
|
package/dist/memory/store.js
CHANGED
|
@@ -17,6 +17,7 @@ import { extractFromMemory } from '../graph/extract.js';
|
|
|
17
17
|
import { processExtractionResult } from '../graph/resolve.js';
|
|
18
18
|
import { runDefencePipeline, storeFragmentationData } from '../defence/index.js';
|
|
19
19
|
import { syncQuarantineToCloud } from '../cloud/quarantine-sync.js';
|
|
20
|
+
import { isFeatureEnabled } from '../license/gate.js';
|
|
20
21
|
import { checkAccess } from '../defence/trust/access-control.js';
|
|
21
22
|
import { scoreSource } from '../defence/trust/source-scorer.js';
|
|
22
23
|
import { logAudit } from '../defence/audit/logger.js';
|
|
@@ -287,22 +288,23 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
287
288
|
defenceResult.firewall.reason = `Sub-agent write (trust=${trust.toFixed(3)}) requires parent approval`;
|
|
288
289
|
// Pipeline returned ALLOW so pipeline.ts didn't sync quarantine content.
|
|
289
290
|
// Sync it now since we've overridden to QUARANTINE post-pipeline.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
291
|
+
if (isFeatureEnabled('cloud_sync'))
|
|
292
|
+
try {
|
|
293
|
+
const indicators = defenceResult.firewall.threatIndicators.map(t => typeof t === 'string' ? t : t.pattern ?? String(t));
|
|
294
|
+
syncQuarantineToCloud({
|
|
295
|
+
original_content: input.content,
|
|
296
|
+
original_title: input.title,
|
|
297
|
+
source_type: source.type,
|
|
298
|
+
source_identifier: source.identifier,
|
|
299
|
+
reason: defenceResult.firewall.reason,
|
|
300
|
+
threat_indicators: indicators,
|
|
301
|
+
anomaly_score: defenceResult.firewall.anomalyScore,
|
|
302
|
+
firewall_result: defenceResult.firewall.result,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Cloud sync must never affect local quarantine flow
|
|
307
|
+
}
|
|
306
308
|
}
|
|
307
309
|
if (!defenceResult.allowed) {
|
|
308
310
|
// Store in quarantine instead of memory
|