sekant-intercept-js 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,230 @@
1
+ /*
2
+ * Copyright 2026 Rishi Kant (Sekant Security Inc.)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * Sekant Intercept Custom Modules Interface
19
+ *
20
+ * This file defines the interface for custom modules that can be registered
21
+ * with the InterceptScanner. Custom modules extend functionality beyond the
22
+ * standard modules (pe, elf, math, hash, string, time).
23
+ *
24
+ * ============================================================================
25
+ * MODULE LIFECYCLE
26
+ * ============================================================================
27
+ *
28
+ * 1. load()
29
+ * - Called once when module needs initialization (lazy loading during first scan)
30
+ * - Use for: fetching databases, compiling patterns, loading resources
31
+ * - Must catch errors internally and set loaded flag to false on failure
32
+ *
33
+ * 2. initialize(data, metadata)
34
+ * - Called per scan to process the file data
35
+ * - Receives: Uint8Array data and metadata object
36
+ * - Returns: Interim results object (any structure you need)
37
+ * - Must return {} if module not loaded
38
+ *
39
+ * 3. createModule(interimResults)
40
+ * - Called per scan to create final module object for condition evaluation
41
+ * - Receives: Results from initialize()
42
+ * - Returns: Object with properties/functions accessible in YARA conditions
43
+ * - Must return {} if module not loaded
44
+ *
45
+ * ============================================================================
46
+ * REQUIRED INTERFACE
47
+ * ============================================================================
48
+ *
49
+ * getName(): string
50
+ * - Returns module keyword used in YARA conditions (e.g., "mymodule")
51
+ * - Must be lowercase alphanumeric for consistency
52
+ * - Cannot conflict with reserved names (see RESERVED_MODULE_NAMES)
53
+ *
54
+ * isLoaded(): boolean
55
+ * - Returns whether load() completed successfully
56
+ * - Used by scanner to determine if load() needs to be called
57
+ *
58
+ * load(): Promise<void>
59
+ * - One-time initialization
60
+ * - Should catch errors and set internal loaded flag to false
61
+ * - Called lazily on first scan if isLoaded() returns false
62
+ *
63
+ * initialize(data, metadata): Promise<Object>
64
+ * - Process file data and return interim results
65
+ * - data: Uint8Array of file being scanned
66
+ * - metadata: {filesize, hasPE, hasELF, timestamp, ...}
67
+ * - Must return {} if not loaded
68
+ *
69
+ * createModule(interimResults): Object
70
+ * - Create final module object from interim results
71
+ * - Returns object with properties/functions for conditions
72
+ * - Must return {} if not loaded
73
+ *
74
+ * ============================================================================
75
+ * USAGE IN YARA RULES
76
+ * ============================================================================
77
+ *
78
+ * rule ExampleRule {
79
+ * condition:
80
+ * mymodule.property == value and
81
+ * mymodule.method(arg1, arg2)
82
+ * }
83
+ *
84
+ * ============================================================================
85
+ * ERROR HANDLING
86
+ * ============================================================================
87
+ *
88
+ * - load() failures: Catch internally, set loaded=false, log warning
89
+ * - initialize() failures: Return {}, log warning
90
+ * - createModule() failures: Return {}
91
+ * - Graceful degradation: Conditions using unavailable modules → undefined/false
92
+ *
93
+ * ============================================================================
94
+ * MODULE NAME RESTRICTIONS
95
+ * ============================================================================
96
+ *
97
+ * Cannot use reserved keywords (case-insensitive):
98
+ * pe, elf, math, hash, string, time, filesize, entrypoint
99
+ */
100
+
101
+ /**
102
+ * Base Custom Module Class
103
+ *
104
+ * Extend this class to create your custom module. Override all methods.
105
+ *
106
+ * @example
107
+ * class MyModule extends BaseCustomModule {
108
+ * constructor() {
109
+ * super();
110
+ * this._loaded = false;
111
+ * }
112
+ *
113
+ * getName() {
114
+ * return 'mymodule';
115
+ * }
116
+ *
117
+ * isLoaded() {
118
+ * return this._loaded;
119
+ * }
120
+ *
121
+ * async load() {
122
+ * try {
123
+ * // Your initialization logic
124
+ * this._loaded = true;
125
+ * } catch (error) {
126
+ * console.warn(`MyModule: Load failed: ${error.message}`);
127
+ * this._loaded = false;
128
+ * }
129
+ * }
130
+ *
131
+ * async initialize(data, metadata) {
132
+ * if (!this._loaded) return {};
133
+ * // Process data and return results
134
+ * return { result: 'value' };
135
+ * }
136
+ *
137
+ * createModule(interimResults) {
138
+ * if (!this._loaded) return {};
139
+ * return {
140
+ * property: interimResults.result,
141
+ * method: (arg) => arg * 2,
142
+ * };
143
+ * }
144
+ * }
145
+ */
146
+ export class BaseCustomModule {
147
+
148
+ constructor(name) {
149
+ // Initialization logic if needed
150
+ this._isLoaded = false;
151
+ this._name = name;
152
+ if (!isValidModuleName(name)) {
153
+ throw new Error(`Invalid module name: "${name}". It is either reserved or malformed.`);
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Returns the module keyword for YARA conditions
159
+ * @returns {string} Module name (must be unique and not reserved)
160
+ */
161
+ getName() {
162
+ return this._name;
163
+ }
164
+
165
+ /**
166
+ * Returns whether the module loaded successfully
167
+ * @returns {boolean} Load status
168
+ */
169
+ isLoaded() {
170
+ return this._isLoaded;
171
+ }
172
+
173
+ /**
174
+ * One-time initialization
175
+ * Should catch errors internally and set loaded flag
176
+ * @returns {Promise<boolean>} Load success status
177
+ */
178
+ async load() {
179
+ this._isLoaded = true;
180
+ return this._isLoaded;
181
+ }
182
+
183
+ /**
184
+ * Process file data per scan
185
+ * @param {Uint8Array} data - File data being scanned
186
+ * @param {Object} metadata - Scan metadata (filesize, hasPE, hasELF, timestamp)
187
+ * @returns {Promise<Object>} Interim results (any structure)
188
+ */
189
+ async initialize(data, metadata) { // eslint-disable-line no-unused-vars
190
+ throw new Error('CustomModule.initialize() must be implemented');
191
+ }
192
+
193
+ /**
194
+ * Create final module object for condition evaluation
195
+ * @param {Object} interimResults - Results from initialize()
196
+ * @returns {Object} Module object with properties and/or functions
197
+ */
198
+ createModule(interimResults) { // eslint-disable-line no-unused-vars
199
+ throw new Error('CustomModule.createModule() must be implemented');
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Reserved Module Keywords (case-insensitive)
205
+ * These names cannot be used for custom modules
206
+ */
207
+ export const RESERVED_MODULE_NAMES = [
208
+ 'pe',
209
+ 'elf',
210
+ 'math',
211
+ 'hash',
212
+ 'string',
213
+ 'time',
214
+ 'filesize',
215
+ 'entrypoint',
216
+ ];
217
+
218
+ /**
219
+ * Validate custom module name against reserved keywords
220
+ * @param {string} name - Module name to validate
221
+ * @returns {boolean} True if name is valid (not reserved)
222
+ */
223
+ export function isValidModuleName(name) {
224
+ if (!name || typeof name !== 'string') {
225
+ return false;
226
+ }
227
+
228
+ const nameLower = name.toLowerCase();
229
+ return !RESERVED_MODULE_NAMES.includes(nameLower);
230
+ }