@anomira/node-sdk 0.1.9 → 0.2.2
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 +297 -130
- package/dist/index.cjs +1204 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -6
- package/dist/index.d.ts +102 -6
- package/dist/index.js +1204 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -78,6 +78,43 @@ interface AnomiraConfig {
|
|
|
78
78
|
* Default: reads X-Forwarded-For → X-Real-IP → socket.remoteAddress
|
|
79
79
|
*/
|
|
80
80
|
getIp?: (req: unknown) => string;
|
|
81
|
+
/**
|
|
82
|
+
* Invisible security — automatic blocking from Anomira's community
|
|
83
|
+
* threat intelligence network.
|
|
84
|
+
*
|
|
85
|
+
* When enabled (the default), the SDK periodically fetches high-confidence
|
|
86
|
+
* attacker IPs from the Anomira network — IPs that have been seen attacking
|
|
87
|
+
* multiple customers — and blocks them automatically, without any manual
|
|
88
|
+
* decision required.
|
|
89
|
+
*
|
|
90
|
+
* This is the "invisible" part: your API is protected from known bad actors
|
|
91
|
+
* the moment they appear in the network, before they even reach your handlers.
|
|
92
|
+
*
|
|
93
|
+
* Set `enabled: false` to disable auto-blocking and use threat data for
|
|
94
|
+
* alerting only (the data is still fetched and logged).
|
|
95
|
+
*/
|
|
96
|
+
autoBlock?: {
|
|
97
|
+
/**
|
|
98
|
+
* Whether to automatically block IPs from the community threat network.
|
|
99
|
+
* @default true
|
|
100
|
+
*/
|
|
101
|
+
enabled?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Minimum community confidence score (0-100) to trigger an auto-block.
|
|
104
|
+
* Only IPs above this threshold are blocked automatically.
|
|
105
|
+
*
|
|
106
|
+
* @default 85
|
|
107
|
+
*
|
|
108
|
+
* Guidance:
|
|
109
|
+
* 85 (default) — confirmed malicious across multiple customers, very low false-positive risk
|
|
110
|
+
* 70 — broader coverage, slightly higher false-positive risk
|
|
111
|
+
* 95 — maximum precision, only the most confirmed threats
|
|
112
|
+
*
|
|
113
|
+
* Do not set below 60 — scores below that reflect limited data and carry
|
|
114
|
+
* meaningful false-positive risk.
|
|
115
|
+
*/
|
|
116
|
+
communityThreshold?: number;
|
|
117
|
+
};
|
|
81
118
|
}
|
|
82
119
|
interface SdkEvent {
|
|
83
120
|
name: string;
|
|
@@ -150,22 +187,41 @@ interface FirewallRule {
|
|
|
150
187
|
*/
|
|
151
188
|
declare class AnomiraClient {
|
|
152
189
|
#private;
|
|
153
|
-
readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect">> & {
|
|
190
|
+
readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect" | "autoBlock">> & {
|
|
154
191
|
getUserId: NonNullable<AnomiraConfig["getUserId"]>;
|
|
155
192
|
getIp: NonNullable<AnomiraConfig["getIp"]>;
|
|
156
193
|
detect: Required<NonNullable<AnomiraConfig["detect"]>>;
|
|
157
194
|
captureConsole: boolean;
|
|
158
195
|
service: string;
|
|
196
|
+
autoBlock: Required<NonNullable<AnomiraConfig["autoBlock"]>>;
|
|
159
197
|
};
|
|
160
198
|
private readonly buffer;
|
|
161
199
|
private readonly logBuffer;
|
|
162
200
|
private logFlushTimer;
|
|
163
201
|
private blocklistTimer;
|
|
164
202
|
private firewallTimer;
|
|
203
|
+
private communityThreatTimer;
|
|
165
204
|
/** True when credentials are missing — all operations become no-ops. */
|
|
166
205
|
private disabled;
|
|
167
|
-
/** In-process cache of blocked IPs — refreshed every 60 s
|
|
206
|
+
/** In-process cache of manually blocked IPs — refreshed every 60 s. */
|
|
168
207
|
private blockedIpCache;
|
|
208
|
+
/** In-process cache of community threat IPs with their confidence scores.
|
|
209
|
+
* Populated from Anomira's federated threat network — IPs confirmed malicious
|
|
210
|
+
* across multiple customers. Refreshed every 60 s. */
|
|
211
|
+
private communityThreatCache;
|
|
212
|
+
/**
|
|
213
|
+
* Set of honeypot paths to intercept. When a request matches, the SDK returns
|
|
214
|
+
* a fake response instead of forwarding to the customer's route handlers.
|
|
215
|
+
* Synced from ingest every 60 s. Keys are lowercase path strings.
|
|
216
|
+
*/
|
|
217
|
+
private honeypotPaths;
|
|
218
|
+
/**
|
|
219
|
+
* Set of active canary token strings embedded in previously-served honeypot
|
|
220
|
+
* responses. When any of these appear in a request's Authorization header or
|
|
221
|
+
* body, a http.canary.triggered event is fired.
|
|
222
|
+
* Synced from ingest every 60 s (max 100 tokens, sliding 7-day window).
|
|
223
|
+
*/
|
|
224
|
+
private canaryTokenCache;
|
|
169
225
|
/** In-process cache of firewall rules with pre-compiled regex — refreshed every 60 s. */
|
|
170
226
|
private compiledRules;
|
|
171
227
|
private readonly _origLog;
|
|
@@ -184,8 +240,37 @@ declare class AnomiraClient {
|
|
|
184
240
|
* });
|
|
185
241
|
* ```
|
|
186
242
|
*/
|
|
187
|
-
/**
|
|
243
|
+
/**
|
|
244
|
+
* Returns true if the IP should be blocked. Synchronous — no network call.
|
|
245
|
+
*
|
|
246
|
+
* Checks two independent sources:
|
|
247
|
+
* 1. Manual blocklist — IPs explicitly blocked by the customer or via playbooks.
|
|
248
|
+
* 2. Community threats — IPs from Anomira's federated network whose confidence
|
|
249
|
+
* score meets the autoBlock.communityThreshold (default 85).
|
|
250
|
+
* Only active when autoBlock.enabled is true (the default).
|
|
251
|
+
*
|
|
252
|
+
* If a customer sets autoBlock.enabled = false, only the manual blocklist is checked.
|
|
253
|
+
*/
|
|
188
254
|
isBlocked(ip: string): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Returns the block reason for an IP — useful for logging or custom responses.
|
|
257
|
+
* Returns null if the IP is not blocked.
|
|
258
|
+
*/
|
|
259
|
+
blockReason(ip: string): {
|
|
260
|
+
source: "manual" | "community";
|
|
261
|
+
score?: number;
|
|
262
|
+
topAttack?: string;
|
|
263
|
+
} | null;
|
|
264
|
+
/**
|
|
265
|
+
* Fire-and-forget: report a blocked-IP attempt to the ingest server so the
|
|
266
|
+
* dashboard can show that the block is actively working.
|
|
267
|
+
* Called automatically by the Express/Fastify middleware — no manual call needed.
|
|
268
|
+
*/
|
|
269
|
+
reportBlockedHit(ip: string, meta: {
|
|
270
|
+
method: string;
|
|
271
|
+
url: string;
|
|
272
|
+
userAgent: string;
|
|
273
|
+
}): void;
|
|
189
274
|
/** Evaluate firewall rules against a request. Returns the matched rule or null. Synchronous. */
|
|
190
275
|
matchFirewallRule(req: {
|
|
191
276
|
url: string;
|
|
@@ -196,7 +281,18 @@ declare class AnomiraClient {
|
|
|
196
281
|
rule: FirewallRule;
|
|
197
282
|
} | null;
|
|
198
283
|
track(eventName: string, data: {
|
|
199
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Client IP address. Optional — when omitted or empty the SDK
|
|
286
|
+
* automatically reads it from the active request context set by the
|
|
287
|
+
* Express/Fastify middleware. This means developers calling track()
|
|
288
|
+
* inside a request handler get the correct IP for free, with no extra
|
|
289
|
+
* configuration required.
|
|
290
|
+
*
|
|
291
|
+
* Only pass this explicitly when calling track() outside a request
|
|
292
|
+
* context (e.g. from a background job or a webhook handler that has
|
|
293
|
+
* the IP available separately).
|
|
294
|
+
*/
|
|
295
|
+
ip?: string;
|
|
200
296
|
userId?: string;
|
|
201
297
|
meta?: Record<string, unknown>;
|
|
202
298
|
}): void;
|
|
@@ -213,7 +309,7 @@ declare class AnomiraClient {
|
|
|
213
309
|
* ```
|
|
214
310
|
*/
|
|
215
311
|
trackLogin(data: {
|
|
216
|
-
ip
|
|
312
|
+
ip?: string;
|
|
217
313
|
userId: string;
|
|
218
314
|
meta?: Record<string, unknown>;
|
|
219
315
|
}): Promise<void>;
|
|
@@ -232,7 +328,7 @@ declare class AnomiraClient {
|
|
|
232
328
|
* ```
|
|
233
329
|
*/
|
|
234
330
|
trackPhoneAuth(data: {
|
|
235
|
-
ip
|
|
331
|
+
ip?: string;
|
|
236
332
|
userId: string;
|
|
237
333
|
phone: string;
|
|
238
334
|
meta?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,43 @@ interface AnomiraConfig {
|
|
|
78
78
|
* Default: reads X-Forwarded-For → X-Real-IP → socket.remoteAddress
|
|
79
79
|
*/
|
|
80
80
|
getIp?: (req: unknown) => string;
|
|
81
|
+
/**
|
|
82
|
+
* Invisible security — automatic blocking from Anomira's community
|
|
83
|
+
* threat intelligence network.
|
|
84
|
+
*
|
|
85
|
+
* When enabled (the default), the SDK periodically fetches high-confidence
|
|
86
|
+
* attacker IPs from the Anomira network — IPs that have been seen attacking
|
|
87
|
+
* multiple customers — and blocks them automatically, without any manual
|
|
88
|
+
* decision required.
|
|
89
|
+
*
|
|
90
|
+
* This is the "invisible" part: your API is protected from known bad actors
|
|
91
|
+
* the moment they appear in the network, before they even reach your handlers.
|
|
92
|
+
*
|
|
93
|
+
* Set `enabled: false` to disable auto-blocking and use threat data for
|
|
94
|
+
* alerting only (the data is still fetched and logged).
|
|
95
|
+
*/
|
|
96
|
+
autoBlock?: {
|
|
97
|
+
/**
|
|
98
|
+
* Whether to automatically block IPs from the community threat network.
|
|
99
|
+
* @default true
|
|
100
|
+
*/
|
|
101
|
+
enabled?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Minimum community confidence score (0-100) to trigger an auto-block.
|
|
104
|
+
* Only IPs above this threshold are blocked automatically.
|
|
105
|
+
*
|
|
106
|
+
* @default 85
|
|
107
|
+
*
|
|
108
|
+
* Guidance:
|
|
109
|
+
* 85 (default) — confirmed malicious across multiple customers, very low false-positive risk
|
|
110
|
+
* 70 — broader coverage, slightly higher false-positive risk
|
|
111
|
+
* 95 — maximum precision, only the most confirmed threats
|
|
112
|
+
*
|
|
113
|
+
* Do not set below 60 — scores below that reflect limited data and carry
|
|
114
|
+
* meaningful false-positive risk.
|
|
115
|
+
*/
|
|
116
|
+
communityThreshold?: number;
|
|
117
|
+
};
|
|
81
118
|
}
|
|
82
119
|
interface SdkEvent {
|
|
83
120
|
name: string;
|
|
@@ -150,22 +187,41 @@ interface FirewallRule {
|
|
|
150
187
|
*/
|
|
151
188
|
declare class AnomiraClient {
|
|
152
189
|
#private;
|
|
153
|
-
readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect">> & {
|
|
190
|
+
readonly config: Required<Omit<AnomiraConfig, "getUserId" | "getIp" | "detect" | "autoBlock">> & {
|
|
154
191
|
getUserId: NonNullable<AnomiraConfig["getUserId"]>;
|
|
155
192
|
getIp: NonNullable<AnomiraConfig["getIp"]>;
|
|
156
193
|
detect: Required<NonNullable<AnomiraConfig["detect"]>>;
|
|
157
194
|
captureConsole: boolean;
|
|
158
195
|
service: string;
|
|
196
|
+
autoBlock: Required<NonNullable<AnomiraConfig["autoBlock"]>>;
|
|
159
197
|
};
|
|
160
198
|
private readonly buffer;
|
|
161
199
|
private readonly logBuffer;
|
|
162
200
|
private logFlushTimer;
|
|
163
201
|
private blocklistTimer;
|
|
164
202
|
private firewallTimer;
|
|
203
|
+
private communityThreatTimer;
|
|
165
204
|
/** True when credentials are missing — all operations become no-ops. */
|
|
166
205
|
private disabled;
|
|
167
|
-
/** In-process cache of blocked IPs — refreshed every 60 s
|
|
206
|
+
/** In-process cache of manually blocked IPs — refreshed every 60 s. */
|
|
168
207
|
private blockedIpCache;
|
|
208
|
+
/** In-process cache of community threat IPs with their confidence scores.
|
|
209
|
+
* Populated from Anomira's federated threat network — IPs confirmed malicious
|
|
210
|
+
* across multiple customers. Refreshed every 60 s. */
|
|
211
|
+
private communityThreatCache;
|
|
212
|
+
/**
|
|
213
|
+
* Set of honeypot paths to intercept. When a request matches, the SDK returns
|
|
214
|
+
* a fake response instead of forwarding to the customer's route handlers.
|
|
215
|
+
* Synced from ingest every 60 s. Keys are lowercase path strings.
|
|
216
|
+
*/
|
|
217
|
+
private honeypotPaths;
|
|
218
|
+
/**
|
|
219
|
+
* Set of active canary token strings embedded in previously-served honeypot
|
|
220
|
+
* responses. When any of these appear in a request's Authorization header or
|
|
221
|
+
* body, a http.canary.triggered event is fired.
|
|
222
|
+
* Synced from ingest every 60 s (max 100 tokens, sliding 7-day window).
|
|
223
|
+
*/
|
|
224
|
+
private canaryTokenCache;
|
|
169
225
|
/** In-process cache of firewall rules with pre-compiled regex — refreshed every 60 s. */
|
|
170
226
|
private compiledRules;
|
|
171
227
|
private readonly _origLog;
|
|
@@ -184,8 +240,37 @@ declare class AnomiraClient {
|
|
|
184
240
|
* });
|
|
185
241
|
* ```
|
|
186
242
|
*/
|
|
187
|
-
/**
|
|
243
|
+
/**
|
|
244
|
+
* Returns true if the IP should be blocked. Synchronous — no network call.
|
|
245
|
+
*
|
|
246
|
+
* Checks two independent sources:
|
|
247
|
+
* 1. Manual blocklist — IPs explicitly blocked by the customer or via playbooks.
|
|
248
|
+
* 2. Community threats — IPs from Anomira's federated network whose confidence
|
|
249
|
+
* score meets the autoBlock.communityThreshold (default 85).
|
|
250
|
+
* Only active when autoBlock.enabled is true (the default).
|
|
251
|
+
*
|
|
252
|
+
* If a customer sets autoBlock.enabled = false, only the manual blocklist is checked.
|
|
253
|
+
*/
|
|
188
254
|
isBlocked(ip: string): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Returns the block reason for an IP — useful for logging or custom responses.
|
|
257
|
+
* Returns null if the IP is not blocked.
|
|
258
|
+
*/
|
|
259
|
+
blockReason(ip: string): {
|
|
260
|
+
source: "manual" | "community";
|
|
261
|
+
score?: number;
|
|
262
|
+
topAttack?: string;
|
|
263
|
+
} | null;
|
|
264
|
+
/**
|
|
265
|
+
* Fire-and-forget: report a blocked-IP attempt to the ingest server so the
|
|
266
|
+
* dashboard can show that the block is actively working.
|
|
267
|
+
* Called automatically by the Express/Fastify middleware — no manual call needed.
|
|
268
|
+
*/
|
|
269
|
+
reportBlockedHit(ip: string, meta: {
|
|
270
|
+
method: string;
|
|
271
|
+
url: string;
|
|
272
|
+
userAgent: string;
|
|
273
|
+
}): void;
|
|
189
274
|
/** Evaluate firewall rules against a request. Returns the matched rule or null. Synchronous. */
|
|
190
275
|
matchFirewallRule(req: {
|
|
191
276
|
url: string;
|
|
@@ -196,7 +281,18 @@ declare class AnomiraClient {
|
|
|
196
281
|
rule: FirewallRule;
|
|
197
282
|
} | null;
|
|
198
283
|
track(eventName: string, data: {
|
|
199
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Client IP address. Optional — when omitted or empty the SDK
|
|
286
|
+
* automatically reads it from the active request context set by the
|
|
287
|
+
* Express/Fastify middleware. This means developers calling track()
|
|
288
|
+
* inside a request handler get the correct IP for free, with no extra
|
|
289
|
+
* configuration required.
|
|
290
|
+
*
|
|
291
|
+
* Only pass this explicitly when calling track() outside a request
|
|
292
|
+
* context (e.g. from a background job or a webhook handler that has
|
|
293
|
+
* the IP available separately).
|
|
294
|
+
*/
|
|
295
|
+
ip?: string;
|
|
200
296
|
userId?: string;
|
|
201
297
|
meta?: Record<string, unknown>;
|
|
202
298
|
}): void;
|
|
@@ -213,7 +309,7 @@ declare class AnomiraClient {
|
|
|
213
309
|
* ```
|
|
214
310
|
*/
|
|
215
311
|
trackLogin(data: {
|
|
216
|
-
ip
|
|
312
|
+
ip?: string;
|
|
217
313
|
userId: string;
|
|
218
314
|
meta?: Record<string, unknown>;
|
|
219
315
|
}): Promise<void>;
|
|
@@ -232,7 +328,7 @@ declare class AnomiraClient {
|
|
|
232
328
|
* ```
|
|
233
329
|
*/
|
|
234
330
|
trackPhoneAuth(data: {
|
|
235
|
-
ip
|
|
331
|
+
ip?: string;
|
|
236
332
|
userId: string;
|
|
237
333
|
phone: string;
|
|
238
334
|
meta?: Record<string, unknown>;
|