@sentriflow/core 0.1.9 → 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.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * GRX2 Extended Loader Module
3
+ *
4
+ * Provides functionality for loading and decrypting extended GRX2 encrypted rule packs.
5
+ * This module is used by both the CLI and VS Code extension.
6
+ *
7
+ * @module @sentriflow/core/grx2-loader
8
+ */
9
+
10
+ // Types
11
+ export type {
12
+ LicensePayload,
13
+ GRX2ExtendedHeader,
14
+ WrappedTMK,
15
+ SerializedWrappedTMK,
16
+ EncryptedPackInfo,
17
+ GRX2PackLoadResult,
18
+ EncryptedPackErrorCode,
19
+ } from './types';
20
+
21
+ // Error class
22
+ export { EncryptedPackError } from './types';
23
+
24
+ // Constants
25
+ export {
26
+ GRX2_HEADER_SIZE,
27
+ GRX2_EXTENDED_VERSION,
28
+ GRX2_EXTENDED_FLAG,
29
+ GRX2_PORTABLE_FLAG,
30
+ GRX2_ALGORITHM_AES_256_GCM,
31
+ GRX2_KDF_PBKDF2,
32
+ GRX2_KEY_TYPE_TMK,
33
+ GRX2_KEY_TYPE_CTMK,
34
+ DEFAULT_PACKS_DIRECTORY,
35
+ CACHE_DIRECTORY,
36
+ } from './types';
37
+
38
+ // Machine ID functions
39
+ export { getMachineId, getMachineIdSync } from './MachineId';
40
+
41
+ // Loader functions
42
+ export {
43
+ isExtendedGRX2,
44
+ loadExtendedPack,
45
+ loadAllPacks,
46
+ getPackInfo,
47
+ } from './GRX2ExtendedLoader';
@@ -0,0 +1,277 @@
1
+ /**
2
+ * GRX2 Extended Loader Types
3
+ *
4
+ * Types for encrypted GRX2 rule pack loading.
5
+ * Used by both CLI and VS Code extension.
6
+ *
7
+ * @module @sentriflow/core/grx2-loader/types
8
+ */
9
+
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+
13
+ // =============================================================================
14
+ // License Types
15
+ // =============================================================================
16
+
17
+ /**
18
+ * JWT License payload structure
19
+ *
20
+ * The license key is a JWT containing this payload.
21
+ * It can be decoded offline to get entitlements.
22
+ */
23
+ export interface LicensePayload {
24
+ /** Customer ID (JWT subject) */
25
+ sub: string;
26
+
27
+ /** Customer tier */
28
+ tier: 'community' | 'professional' | 'enterprise';
29
+
30
+ /** Entitled feed IDs */
31
+ feeds: string[];
32
+
33
+ /** API URL for cloud updates */
34
+ api: string;
35
+
36
+ /** Expiration timestamp (Unix seconds) */
37
+ exp: number;
38
+
39
+ /** Issued at timestamp (Unix seconds) */
40
+ iat: number;
41
+
42
+ /** Optional machine ID binding */
43
+ mid?: string;
44
+
45
+ /** Optional customer name */
46
+ name?: string;
47
+ }
48
+
49
+ // =============================================================================
50
+ // GRX2 Extended Format Types
51
+ // =============================================================================
52
+
53
+ /**
54
+ * Extended GRX2 header structure (96 bytes)
55
+ *
56
+ * The extended format uses version=3 and includes a wrapped TMK block
57
+ * after the standard header.
58
+ */
59
+ export interface GRX2ExtendedHeader {
60
+ /** Magic bytes ("GRX2") */
61
+ magic: Buffer;
62
+
63
+ /** Format version (3 for extended) */
64
+ version: number;
65
+
66
+ /** Encryption algorithm (1 = AES-256-GCM) */
67
+ algorithm: number;
68
+
69
+ /** Key derivation function (1 = PBKDF2) */
70
+ kdf: number;
71
+
72
+ /** Key type (1 = TMK, 2 = CTMK) */
73
+ keyType: number;
74
+
75
+ /** Tier ID */
76
+ tierId: number;
77
+
78
+ /** TMK version */
79
+ tmkVersion: number;
80
+
81
+ /** Initialization vector (12 bytes) */
82
+ iv: Buffer;
83
+
84
+ /** Authentication tag (16 bytes) */
85
+ authTag: Buffer;
86
+
87
+ /** PBKDF2 salt (32 bytes, zeros for TMK mode) */
88
+ salt: Buffer;
89
+
90
+ /** Encrypted payload length */
91
+ payloadLength: number;
92
+
93
+ /** Pack hash (16 bytes, truncated SHA-256) */
94
+ packHash: Buffer;
95
+
96
+ /** Reserved bytes */
97
+ reserved: Buffer;
98
+
99
+ /** Indicates extended format */
100
+ isExtended: true;
101
+
102
+ /** Indicates portable pack (no machine binding required) */
103
+ isPortable: boolean;
104
+
105
+ /** Wrapped TMK embedded in pack */
106
+ wrappedTMK: WrappedTMK;
107
+
108
+ /** Total header size (96 + 4 + wrapped TMK length) */
109
+ totalHeaderSize: number;
110
+ }
111
+
112
+ /**
113
+ * Wrapped TMK structure
114
+ *
115
+ * TMK encrypted with LDK (derived from license key + salt).
116
+ * Embedded in extended GRX2 packs.
117
+ *
118
+ * SECURITY: Uses random salt for PBKDF2 key derivation.
119
+ * The salt is stored with the wrapped TMK, not derived from predictable values.
120
+ */
121
+ export interface WrappedTMK {
122
+ /** Encrypted TMK (32 bytes encrypted) */
123
+ encryptedKey: Buffer;
124
+
125
+ /** IV used for TMK encryption (12 bytes) */
126
+ iv: Buffer;
127
+
128
+ /** Auth tag for TMK (16 bytes) */
129
+ authTag: Buffer;
130
+
131
+ /** TMK version that was wrapped */
132
+ tmkVersion: number;
133
+
134
+ /**
135
+ * Random salt for LDK derivation (32 bytes)
136
+ * SECURITY: This is a cryptographically random value, NOT derived from machineId.
137
+ * The machineId is used as additional input to the KDF, not as the sole salt.
138
+ */
139
+ ldkSalt: Buffer;
140
+ }
141
+
142
+ /**
143
+ * Serialized wrapped TMK (for JSON storage)
144
+ */
145
+ export interface SerializedWrappedTMK {
146
+ /** Base64-encoded encrypted key */
147
+ k: string;
148
+ /** Base64-encoded IV */
149
+ i: string;
150
+ /** Base64-encoded auth tag */
151
+ t: string;
152
+ /** TMK version */
153
+ v: number;
154
+ /** Base64-encoded LDK salt (32 bytes random) */
155
+ s: string;
156
+ }
157
+
158
+ // =============================================================================
159
+ // Pack Types
160
+ // =============================================================================
161
+
162
+ /**
163
+ * Information about a loaded encrypted pack
164
+ */
165
+ export interface EncryptedPackInfo {
166
+ /** Feed ID */
167
+ feedId: string;
168
+
169
+ /** Pack name */
170
+ name: string;
171
+
172
+ /** Pack version */
173
+ version: string;
174
+
175
+ /** Publisher */
176
+ publisher: string;
177
+
178
+ /** Number of rules in pack */
179
+ ruleCount: number;
180
+
181
+ /** File path of the pack */
182
+ filePath: string;
183
+
184
+ /** Whether pack was loaded successfully */
185
+ loaded: boolean;
186
+
187
+ /** Error message if loading failed */
188
+ error?: string;
189
+
190
+ /** Source: local directory or cloud cache */
191
+ source: 'local' | 'cache';
192
+ }
193
+
194
+ /**
195
+ * GRX2 Pack loading result
196
+ * Named GRX2PackLoadResult to avoid collision with pack-provider's PackLoadResult
197
+ */
198
+ export interface GRX2PackLoadResult {
199
+ /** Whether loading was successful */
200
+ success: boolean;
201
+
202
+ /** Loaded packs */
203
+ packs: EncryptedPackInfo[];
204
+
205
+ /** Total rules loaded */
206
+ totalRules: number;
207
+
208
+ /** Errors encountered */
209
+ errors: string[];
210
+ }
211
+
212
+ // =============================================================================
213
+ // Error Types
214
+ // =============================================================================
215
+
216
+ /**
217
+ * Encrypted pack error codes
218
+ */
219
+ export type EncryptedPackErrorCode =
220
+ | 'LICENSE_MISSING'
221
+ | 'LICENSE_EXPIRED'
222
+ | 'LICENSE_INVALID'
223
+ | 'NOT_ENTITLED'
224
+ | 'PACK_NOT_FOUND'
225
+ | 'PACK_CORRUPTED'
226
+ | 'DECRYPTION_FAILED'
227
+ | 'MACHINE_MISMATCH'
228
+ | 'NETWORK_ERROR'
229
+ | 'API_ERROR';
230
+
231
+ /**
232
+ * Encrypted pack error
233
+ */
234
+ export class EncryptedPackError extends Error {
235
+ constructor(
236
+ message: string,
237
+ public readonly code: EncryptedPackErrorCode,
238
+ public readonly details?: unknown
239
+ ) {
240
+ super(message);
241
+ this.name = 'EncryptedPackError';
242
+ }
243
+ }
244
+
245
+ // =============================================================================
246
+ // Constants
247
+ // =============================================================================
248
+
249
+ /** Standard GRX2 header size */
250
+ export const GRX2_HEADER_SIZE = 96;
251
+
252
+ /** Extended format version */
253
+ export const GRX2_EXTENDED_VERSION = 3;
254
+
255
+ /** Extended format flag in reserved byte (bit 0) */
256
+ export const GRX2_EXTENDED_FLAG = 0x01;
257
+
258
+ /** Portable pack flag in reserved byte (bit 1) - no machine binding */
259
+ export const GRX2_PORTABLE_FLAG = 0x02;
260
+
261
+ /** AES-256-GCM algorithm ID */
262
+ export const GRX2_ALGORITHM_AES_256_GCM = 1;
263
+
264
+ /** PBKDF2 KDF ID */
265
+ export const GRX2_KDF_PBKDF2 = 1;
266
+
267
+ /** TMK key type */
268
+ export const GRX2_KEY_TYPE_TMK = 1;
269
+
270
+ /** CTMK key type */
271
+ export const GRX2_KEY_TYPE_CTMK = 2;
272
+
273
+ /** Default packs directory (platform-aware) */
274
+ export const DEFAULT_PACKS_DIRECTORY = join(homedir(), '.sentriflow', 'packs');
275
+
276
+ /** Cache directory (for downloaded packs, platform-aware) */
277
+ export const CACHE_DIRECTORY = join(homedir(), '.sentriflow', 'cache');