pompelmi 0.35.5 → 1.1.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/.claude/settings.local.json +45 -0
- package/LICENSE +12 -18
- package/README.md +174 -181
- package/eslint.config.mjs +8 -0
- package/package.json +26 -251
- package/src/ClamAVDatabaseUpdater.js +48 -0
- package/src/ClamAVInstaller.js +49 -0
- package/src/ClamAVScanner.js +37 -0
- package/src/ClamdScanner.js +81 -0
- package/src/InstallerCommand.js +11 -0
- package/src/config.js +22 -0
- package/src/constants.js +3 -0
- package/src/favicon.ico +0 -0
- package/src/grapefruit.png +0 -0
- package/src/index.js +5 -0
- package/test_out.txt +74 -0
- package/CHANGELOG.md +0 -71
- package/dist/pompelmi.audit.cjs +0 -128
- package/dist/pompelmi.audit.cjs.map +0 -1
- package/dist/pompelmi.audit.esm.js +0 -107
- package/dist/pompelmi.audit.esm.js.map +0 -1
- package/dist/pompelmi.browser.cjs +0 -1549
- package/dist/pompelmi.browser.cjs.map +0 -1
- package/dist/pompelmi.browser.esm.js +0 -1523
- package/dist/pompelmi.browser.esm.js.map +0 -1
- package/dist/pompelmi.cjs +0 -2591
- package/dist/pompelmi.cjs.map +0 -1
- package/dist/pompelmi.esm.js +0 -2525
- package/dist/pompelmi.esm.js.map +0 -1
- package/dist/pompelmi.hooks.cjs +0 -75
- package/dist/pompelmi.hooks.cjs.map +0 -1
- package/dist/pompelmi.hooks.esm.js +0 -72
- package/dist/pompelmi.hooks.esm.js.map +0 -1
- package/dist/pompelmi.policy-packs.cjs +0 -240
- package/dist/pompelmi.policy-packs.cjs.map +0 -1
- package/dist/pompelmi.policy-packs.esm.js +0 -232
- package/dist/pompelmi.policy-packs.esm.js.map +0 -1
- package/dist/pompelmi.quarantine.cjs +0 -317
- package/dist/pompelmi.quarantine.cjs.map +0 -1
- package/dist/pompelmi.quarantine.esm.js +0 -293
- package/dist/pompelmi.quarantine.esm.js.map +0 -1
- package/dist/pompelmi.react.cjs +0 -1580
- package/dist/pompelmi.react.cjs.map +0 -1
- package/dist/pompelmi.react.esm.js +0 -1553
- package/dist/pompelmi.react.esm.js.map +0 -1
- package/dist/types/audit.d.ts +0 -84
- package/dist/types/browser-index.d.ts +0 -29
- package/dist/types/config.d.ts +0 -143
- package/dist/types/engines/dynamic-taint.d.ts +0 -102
- package/dist/types/engines/hybrid-orchestrator.d.ts +0 -65
- package/dist/types/engines/hybrid-taint-integration.d.ts +0 -129
- package/dist/types/engines/taint-policies.d.ts +0 -84
- package/dist/types/hipaa-compliance.d.ts +0 -110
- package/dist/types/hooks.d.ts +0 -89
- package/dist/types/index.d.ts +0 -29
- package/dist/types/magic.d.ts +0 -7
- package/dist/types/node/scanDir.d.ts +0 -30
- package/dist/types/policy-packs.d.ts +0 -98
- package/dist/types/policy.d.ts +0 -12
- package/dist/types/presets.d.ts +0 -72
- package/dist/types/quarantine/index.d.ts +0 -18
- package/dist/types/quarantine/storage.d.ts +0 -77
- package/dist/types/quarantine/types.d.ts +0 -78
- package/dist/types/quarantine/workflow.d.ts +0 -97
- package/dist/types/react-index.d.ts +0 -13
- package/dist/types/risk.d.ts +0 -18
- package/dist/types/scan/remote.d.ts +0 -12
- package/dist/types/scan.d.ts +0 -17
- package/dist/types/scanners/common-heuristics.d.ts +0 -14
- package/dist/types/scanners/zip-bomb-guard.d.ts +0 -9
- package/dist/types/scanners/zipTraversalGuard.d.ts +0 -19
- package/dist/types/src/audit.d.ts +0 -84
- package/dist/types/src/browser-index.d.ts +0 -29
- package/dist/types/src/config.d.ts +0 -143
- package/dist/types/src/engines/dynamic-taint.d.ts +0 -102
- package/dist/types/src/engines/hybrid-orchestrator.d.ts +0 -65
- package/dist/types/src/engines/hybrid-taint-integration.d.ts +0 -129
- package/dist/types/src/engines/taint-policies.d.ts +0 -84
- package/dist/types/src/hipaa-compliance.d.ts +0 -110
- package/dist/types/src/hooks.d.ts +0 -89
- package/dist/types/src/index.d.ts +0 -29
- package/dist/types/src/magic.d.ts +0 -7
- package/dist/types/src/node/scanDir.d.ts +0 -30
- package/dist/types/src/policy-packs.d.ts +0 -98
- package/dist/types/src/policy.d.ts +0 -12
- package/dist/types/src/presets.d.ts +0 -72
- package/dist/types/src/quarantine/index.d.ts +0 -18
- package/dist/types/src/quarantine/storage.d.ts +0 -77
- package/dist/types/src/quarantine/types.d.ts +0 -78
- package/dist/types/src/quarantine/workflow.d.ts +0 -97
- package/dist/types/src/react-index.d.ts +0 -13
- package/dist/types/src/risk.d.ts +0 -18
- package/dist/types/src/scan/remote.d.ts +0 -12
- package/dist/types/src/scan.d.ts +0 -17
- package/dist/types/src/scanners/common-heuristics.d.ts +0 -14
- package/dist/types/src/scanners/zip-bomb-guard.d.ts +0 -11
- package/dist/types/src/scanners/zipTraversalGuard.d.ts +0 -19
- package/dist/types/src/stream.d.ts +0 -10
- package/dist/types/src/types/decompilation.d.ts +0 -96
- package/dist/types/src/types/taint-tracking.d.ts +0 -495
- package/dist/types/src/types.d.ts +0 -48
- package/dist/types/src/useFileScanner.d.ts +0 -15
- package/dist/types/src/utils/advanced-detection.d.ts +0 -21
- package/dist/types/src/utils/batch-scanner.d.ts +0 -62
- package/dist/types/src/utils/cache-manager.d.ts +0 -95
- package/dist/types/src/utils/export.d.ts +0 -51
- package/dist/types/src/utils/performance-metrics.d.ts +0 -68
- package/dist/types/src/utils/threat-intelligence.d.ts +0 -96
- package/dist/types/src/validate.d.ts +0 -7
- package/dist/types/src/verdict.d.ts +0 -2
- package/dist/types/src/yara/browser.d.ts +0 -7
- package/dist/types/src/yara/index.d.ts +0 -17
- package/dist/types/src/yara/node.d.ts +0 -2
- package/dist/types/src/yara/remote.d.ts +0 -10
- package/dist/types/src/yara-bridge.d.ts +0 -3
- package/dist/types/src/zip.d.ts +0 -13
- package/dist/types/stream.d.ts +0 -10
- package/dist/types/types/decompilation.d.ts +0 -96
- package/dist/types/types/taint-tracking.d.ts +0 -495
- package/dist/types/types.d.ts +0 -48
- package/dist/types/useFileScanner.d.ts +0 -15
- package/dist/types/utils/advanced-detection.d.ts +0 -21
- package/dist/types/utils/batch-scanner.d.ts +0 -62
- package/dist/types/utils/cache-manager.d.ts +0 -95
- package/dist/types/utils/export.d.ts +0 -51
- package/dist/types/utils/performance-metrics.d.ts +0 -68
- package/dist/types/utils/threat-intelligence.d.ts +0 -96
- package/dist/types/validate.d.ts +0 -7
- package/dist/types/verdict.d.ts +0 -2
- package/dist/types/yara/browser.d.ts +0 -7
- package/dist/types/yara/index.d.ts +0 -17
- package/dist/types/yara/node.d.ts +0 -2
- package/dist/types/yara/remote.d.ts +0 -10
- package/dist/types/yara-bridge.d.ts +0 -3
- package/dist/types/zip.d.ts +0 -13
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scan lifecycle hooks for Pompelmi.
|
|
3
|
-
*
|
|
4
|
-
* Hooks let you observe and react to scan events without modifying the scan
|
|
5
|
-
* pipeline itself. They are the recommended integration point for:
|
|
6
|
-
* - logging / metrics collection
|
|
7
|
-
* - alerting on threats
|
|
8
|
-
* - triggering quarantine automatically
|
|
9
|
-
* - OpenTelemetry span creation
|
|
10
|
-
*
|
|
11
|
-
* Usage:
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { scanBytes } from 'pompelmi';
|
|
14
|
-
* import { createScanHooks, withHooks } from 'pompelmi/hooks';
|
|
15
|
-
*
|
|
16
|
-
* const hooks = createScanHooks({
|
|
17
|
-
* onScanComplete(ctx, report) {
|
|
18
|
-
* console.log(ctx.filename, report.verdict, report.durationMs + 'ms');
|
|
19
|
-
* },
|
|
20
|
-
* onThreatDetected(ctx, report) {
|
|
21
|
-
* alertTeam({ file: ctx.filename, verdict: report.verdict });
|
|
22
|
-
* },
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* const scan = withHooks(scanBytes, hooks);
|
|
26
|
-
* const report = await scan(bytes, { ctx: { filename: 'upload.zip' } });
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* @module hooks
|
|
30
|
-
*/
|
|
31
|
-
import type { QuarantineEntry } from "./quarantine/types";
|
|
32
|
-
import type { ScanContext, ScanReport } from "./types";
|
|
33
|
-
export interface ScanStartContext extends ScanContext {
|
|
34
|
-
/** Unique identifier for this scan invocation (useful for correlating logs). */
|
|
35
|
-
scanId?: string;
|
|
36
|
-
/** Timestamp when the scan started (ms since epoch). */
|
|
37
|
-
startedAt: number;
|
|
38
|
-
}
|
|
39
|
-
export interface ScanCompleteContext extends ScanStartContext {
|
|
40
|
-
/** Duration of the scan in milliseconds. */
|
|
41
|
-
durationMs: number;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Callbacks for the scan lifecycle. All hooks are optional.
|
|
45
|
-
*
|
|
46
|
-
* Hooks MUST NOT throw — wrap logic in try/catch if it can fail.
|
|
47
|
-
* Async hooks are fire-and-forget; they do not block the scan result.
|
|
48
|
-
*/
|
|
49
|
-
export interface ScanHooks {
|
|
50
|
-
/**
|
|
51
|
-
* Called immediately before a scan begins.
|
|
52
|
-
*/
|
|
53
|
-
onScanStart?: (ctx: ScanStartContext) => void | Promise<void>;
|
|
54
|
-
/**
|
|
55
|
-
* Called when a scan completes successfully (any verdict, including clean).
|
|
56
|
-
*/
|
|
57
|
-
onScanComplete?: (ctx: ScanCompleteContext, report: ScanReport) => void | Promise<void>;
|
|
58
|
-
/**
|
|
59
|
-
* Called when the scan verdict is 'suspicious' or 'malicious'.
|
|
60
|
-
* Fired in addition to `onScanComplete`.
|
|
61
|
-
*/
|
|
62
|
-
onThreatDetected?: (ctx: ScanCompleteContext, report: ScanReport) => void | Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* Called when a file has been quarantined.
|
|
65
|
-
* Requires wiring with a `QuarantineManager`; not fired automatically by `scanBytes`.
|
|
66
|
-
*/
|
|
67
|
-
onQuarantine?: (entry: QuarantineEntry) => void | Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Called when a scan throws an unexpected error.
|
|
70
|
-
*/
|
|
71
|
-
onScanError?: (ctx: ScanStartContext, error: unknown) => void | Promise<void>;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Create a `ScanHooks` object with optional defaults.
|
|
75
|
-
* This is a thin factory — the value of using it is the inline TS types.
|
|
76
|
-
*/
|
|
77
|
-
export declare function createScanHooks(hooks: ScanHooks): ScanHooks;
|
|
78
|
-
type ScanFn = (bytes: Uint8Array, opts?: {
|
|
79
|
-
ctx?: ScanContext;
|
|
80
|
-
[k: string]: unknown;
|
|
81
|
-
}) => Promise<ScanReport>;
|
|
82
|
-
/**
|
|
83
|
-
* Wrap a scan function with lifecycle hooks.
|
|
84
|
-
*
|
|
85
|
-
* Returns a new function with the same signature that fires the hooks
|
|
86
|
-
* around each scan call.
|
|
87
|
-
*/
|
|
88
|
-
export declare function withHooks(scanFn: ScanFn, hooks: ScanHooks): ScanFn;
|
|
89
|
-
export {};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/index.ts — Primary Node.js entry point for Pompelmi.
|
|
3
|
-
*
|
|
4
|
-
* This is the full API including Node.js-only modules (HIPAA compliance,
|
|
5
|
-
* crypto-based caching and hashing, ZIP streaming, YARA native bindings).
|
|
6
|
-
*
|
|
7
|
-
* For browser-safe usage, import from 'pompelmi/browser'.
|
|
8
|
-
* For React hooks, import from 'pompelmi/react'.
|
|
9
|
-
*/
|
|
10
|
-
export { CONFIG_PRESETS, ConfigManager, createConfig, DEFAULT_CONFIG, getPresetConfig, type ScannerConfig, } from "./config";
|
|
11
|
-
export { type AuditEvent, createHipaaError, getHipaaManager, type HipaaConfig, HipaaTemp, initializeHipaaCompliance, } from "./hipaa-compliance";
|
|
12
|
-
export type { NodeFileEntry, NodeScanOptions } from "./node/scanDir";
|
|
13
|
-
export { DEFAULT_POLICY, definePolicy } from "./policy";
|
|
14
|
-
export { ARCHIVES, CONSERVATIVE_DEFAULT, DOCUMENTS_ONLY, getPolicyPack, IMAGES_ONLY, POLICY_PACKS, type PolicyPackName, STRICT_PUBLIC_UPLOAD, } from "./policy-packs";
|
|
15
|
-
export { type ComposeScannerOptions, composeScanners, createPresetScanner, type NamedScanner, type PresetName, type PresetOptions, } from "./presets";
|
|
16
|
-
export { type ScanOptions, scanBytes, scanFile, scanFiles } from "./scan";
|
|
17
|
-
export { scanFilesWithRemoteYara } from "./scan/remote";
|
|
18
|
-
export { CommonHeuristicsScanner } from "./scanners/common-heuristics";
|
|
19
|
-
export { createZipBombGuard } from "./scanners/zip-bomb-guard";
|
|
20
|
-
export * from "./types";
|
|
21
|
-
export { analyzeNestedArchives, detectObfuscatedScripts, detectPolyglot, } from "./utils/advanced-detection";
|
|
22
|
-
export { BatchScanner, type BatchScanOptions, type BatchScanResult, batchScan, type ScanTask, } from "./utils/batch-scanner";
|
|
23
|
-
export { type CacheEntry, type CacheOptions, type CacheStats, getDefaultCache, resetDefaultCache, ScanCacheManager, } from "./utils/cache-manager";
|
|
24
|
-
export { type ExportFormat, type ExportOptions, exportScanResults, ScanResultExporter, } from "./utils/export";
|
|
25
|
-
export { aggregateScanStats, type PerformanceMetrics, PerformanceTracker, type ScanStatistics, } from "./utils/performance-metrics";
|
|
26
|
-
export { createThreatIntelligence, type EnhancedScanReport, getFileHash, LocalThreatIntelligence, type ThreatInfo, ThreatIntelligenceAggregator, type ThreatIntelligenceSource, } from "./utils/threat-intelligence";
|
|
27
|
-
export { validateFile } from "./validate";
|
|
28
|
-
export { mapMatchesToVerdict } from "./verdict";
|
|
29
|
-
export type { YaraMatch } from "./yara/index";
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { YaraMatch } from "../yara/index";
|
|
2
|
-
export interface NodeScanOptions {
|
|
3
|
-
enableYara?: boolean;
|
|
4
|
-
yaraRules?: string;
|
|
5
|
-
yaraRulesPath?: string;
|
|
6
|
-
includeExtensions?: string[];
|
|
7
|
-
yaraAsync?: boolean;
|
|
8
|
-
maxFileSizeBytes?: number;
|
|
9
|
-
yaraSampleBytes?: number;
|
|
10
|
-
yaraPreferBuffer?: boolean;
|
|
11
|
-
}
|
|
12
|
-
export type NodeYaraVerdict = "malicious" | "suspicious" | "clean";
|
|
13
|
-
export interface NodeYaraResult {
|
|
14
|
-
matches: YaraMatch[];
|
|
15
|
-
status: "scanned" | "skipped" | "error";
|
|
16
|
-
/** per i 'skipped', perché abbiamo saltato */
|
|
17
|
-
reason?: "max-size" | "filtered-ext" | "not-enabled" | "engine-missing" | "error";
|
|
18
|
-
/** come abbiamo scansionato quando status = 'scanned' */
|
|
19
|
-
mode?: "async" | "file" | "buffer" | "buffer-sampled";
|
|
20
|
-
/** verdetto derivato dai match (solo quando status='scanned') */
|
|
21
|
-
verdict?: NodeYaraVerdict;
|
|
22
|
-
}
|
|
23
|
-
export interface NodeFileEntry {
|
|
24
|
-
path: string;
|
|
25
|
-
absPath: string;
|
|
26
|
-
isDir: boolean;
|
|
27
|
-
yara?: NodeYaraResult;
|
|
28
|
-
}
|
|
29
|
-
/** Scansiona una directory in modo ricorsivo, emettendo le entry e (opzionale) i match YARA. */
|
|
30
|
-
export declare function scanDir(root: string, opts?: NodeScanOptions): AsyncGenerator<NodeFileEntry>;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Policy packs for Pompelmi.
|
|
3
|
-
*
|
|
4
|
-
* Pre-configured, named policies for common upload scenarios. Each pack
|
|
5
|
-
* defines the file type allowlist, size limits, and timeout appropriate for
|
|
6
|
-
* its use case.
|
|
7
|
-
*
|
|
8
|
-
* All packs are built on `definePolicy` and are fully overridable:
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { POLICY_PACKS } from 'pompelmi/policy-packs';
|
|
12
|
-
*
|
|
13
|
-
* // Use a pack as-is:
|
|
14
|
-
* const policy = POLICY_PACKS['images-only'];
|
|
15
|
-
*
|
|
16
|
-
* // Or override individual fields:
|
|
17
|
-
* import { definePolicy } from 'pompelmi';
|
|
18
|
-
* const custom = definePolicy({ ...POLICY_PACKS['documents-only'], maxFileSizeBytes: 5 * 1024 * 1024 });
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* These packs are *deterministic* and *descriptor-based* — they do not
|
|
22
|
-
* depend on any external threat intelligence feed.
|
|
23
|
-
*
|
|
24
|
-
* @module policy-packs
|
|
25
|
-
*/
|
|
26
|
-
import { type Policy } from "./policy";
|
|
27
|
-
/**
|
|
28
|
-
* Documents-only policy.
|
|
29
|
-
*
|
|
30
|
-
* Appropriate for: document management APIs, PDF/Office file upload endpoints,
|
|
31
|
-
* data import pipelines.
|
|
32
|
-
*
|
|
33
|
-
* Allowed: PDF, Word (.docx/.doc), Excel (.xlsx/.xls), PowerPoint (.pptx/.ppt),
|
|
34
|
-
* CSV, plain text, JSON, YAML, ODT/ODS/ODP (OpenDocument).
|
|
35
|
-
* Max size: 25 MB.
|
|
36
|
-
*/
|
|
37
|
-
export declare const DOCUMENTS_ONLY: Policy;
|
|
38
|
-
/**
|
|
39
|
-
* Images-only policy.
|
|
40
|
-
*
|
|
41
|
-
* Appropriate for: avatar uploads, product image APIs, content platforms with
|
|
42
|
-
* user-generated imagery.
|
|
43
|
-
*
|
|
44
|
-
* Allowed: JPEG, PNG, GIF, WebP, AVIF, TIFF, BMP, ICO.
|
|
45
|
-
* Max size: 10 MB.
|
|
46
|
-
* Note: SVG is intentionally excluded — inline SVGs can contain scripts.
|
|
47
|
-
*/
|
|
48
|
-
export declare const IMAGES_ONLY: Policy;
|
|
49
|
-
/**
|
|
50
|
-
* Strict public-upload policy.
|
|
51
|
-
*
|
|
52
|
-
* Appropriate for: anonymous or low-trust upload endpoints, public APIs,
|
|
53
|
-
* any surface exposed to untrusted users.
|
|
54
|
-
*
|
|
55
|
-
* Aggressive size limit (5 MB), short timeout, fail-closed, narrow MIME
|
|
56
|
-
* allowlist. Only allows plain images and PDF.
|
|
57
|
-
*/
|
|
58
|
-
export declare const STRICT_PUBLIC_UPLOAD: Policy;
|
|
59
|
-
/**
|
|
60
|
-
* Conservative default policy.
|
|
61
|
-
*
|
|
62
|
-
* A hardened version of the built-in `DEFAULT_POLICY` suitable for
|
|
63
|
-
* production without further customisation. Stricter size limit and
|
|
64
|
-
* shorter timeout than the permissive default.
|
|
65
|
-
*/
|
|
66
|
-
export declare const CONSERVATIVE_DEFAULT: Policy;
|
|
67
|
-
/**
|
|
68
|
-
* Archives policy.
|
|
69
|
-
*
|
|
70
|
-
* Appropriate for: endpoints that accept ZIP, tar, or compressed archives.
|
|
71
|
-
* Combines a generous size allowance with a longer timeout for deep inspection.
|
|
72
|
-
*
|
|
73
|
-
* NOTE: Pair this policy with `createZipBombGuard()` to defend against
|
|
74
|
-
* decompression-bomb attacks:
|
|
75
|
-
*
|
|
76
|
-
* ```ts
|
|
77
|
-
* import { composeScanners, createZipBombGuard, CommonHeuristicsScanner } from 'pompelmi';
|
|
78
|
-
* const scanner = composeScanners(
|
|
79
|
-
* [['zipGuard', createZipBombGuard()], ['heuristics', CommonHeuristicsScanner]]
|
|
80
|
-
* );
|
|
81
|
-
* ```
|
|
82
|
-
*/
|
|
83
|
-
export declare const ARCHIVES: Policy;
|
|
84
|
-
export type PolicyPackName = "documents-only" | "images-only" | "strict-public-upload" | "conservative-default" | "archives";
|
|
85
|
-
/**
|
|
86
|
-
* Named map of all built-in policy packs.
|
|
87
|
-
*
|
|
88
|
-
* ```ts
|
|
89
|
-
* import { POLICY_PACKS } from 'pompelmi/policy-packs';
|
|
90
|
-
* const policy = POLICY_PACKS['strict-public-upload'];
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
export declare const POLICY_PACKS: Record<PolicyPackName, Policy>;
|
|
94
|
-
/**
|
|
95
|
-
* Look up a policy pack by name.
|
|
96
|
-
* Throws if the name is not recognised.
|
|
97
|
-
*/
|
|
98
|
-
export declare function getPolicyPack(name: PolicyPackName): Policy;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface Policy {
|
|
2
|
-
includeExtensions: string[];
|
|
3
|
-
allowedMimeTypes: string[];
|
|
4
|
-
maxFileSizeBytes: number;
|
|
5
|
-
timeoutMs: number;
|
|
6
|
-
concurrency: number;
|
|
7
|
-
failClosed: boolean;
|
|
8
|
-
onScanEvent?: (ev: unknown) => void;
|
|
9
|
-
}
|
|
10
|
-
export type PolicyInput = Partial<Policy>;
|
|
11
|
-
export declare const DEFAULT_POLICY: Policy;
|
|
12
|
-
export declare function definePolicy(input?: PolicyInput): Policy;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { AnalysisDepth, ScanFn, Scanner, Verdict } from "./types";
|
|
2
|
-
export type PresetName = "basic" | "advanced" | "malware-analysis" | "decompilation-basic" | "decompilation-deep" | string;
|
|
3
|
-
export interface PresetOptions {
|
|
4
|
-
yaraRules?: string | string[];
|
|
5
|
-
yaraTimeout?: number;
|
|
6
|
-
enableDecompilation?: boolean;
|
|
7
|
-
decompilationEngine?: "binaryninja-hlil" | "ghidra-pcode" | "both";
|
|
8
|
-
decompilationDepth?: AnalysisDepth;
|
|
9
|
-
decompilationTimeout?: number;
|
|
10
|
-
binaryNinjaPath?: string;
|
|
11
|
-
pythonPath?: string;
|
|
12
|
-
ghidraPath?: string;
|
|
13
|
-
analyzeHeadless?: string;
|
|
14
|
-
timeout?: number;
|
|
15
|
-
[key: string]: unknown;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* A named scanner entry used with the array form of `composeScanners`.
|
|
19
|
-
* The first element is a display name for the scanner (used when
|
|
20
|
-
* `tagSourceName: true`), and the second element is the scanner itself.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* const entry: NamedScanner = ['zipGuard', createZipBombGuard({ ... })];
|
|
24
|
-
*/
|
|
25
|
-
export type NamedScanner = [name: string, scanner: Scanner];
|
|
26
|
-
/**
|
|
27
|
-
* Options for `composeScanners` when using the named-scanner array form.
|
|
28
|
-
*/
|
|
29
|
-
export interface ComposeScannerOptions {
|
|
30
|
-
/**
|
|
31
|
-
* When `true` scanners run concurrently (Promise.all).
|
|
32
|
-
* When `false` (default) they run sequentially in order.
|
|
33
|
-
*/
|
|
34
|
-
parallel?: boolean;
|
|
35
|
-
/**
|
|
36
|
-
* Stop scanning as soon as a match at this severity level (or higher) is
|
|
37
|
-
* found. Severity order: `'malicious'` > `'suspicious'` > `'clean'`.
|
|
38
|
-
* Only effective when `parallel` is `false`.
|
|
39
|
-
*/
|
|
40
|
-
stopOn?: Verdict;
|
|
41
|
-
/** Maximum time in milliseconds to wait for each individual scanner. */
|
|
42
|
-
timeoutMsPerScanner?: number;
|
|
43
|
-
/**
|
|
44
|
-
* When `true`, each match is tagged with the scanner's display name via
|
|
45
|
-
* `match.meta._sourceName`. Useful for tracing which scanner produced a
|
|
46
|
-
* given result.
|
|
47
|
-
*/
|
|
48
|
-
tagSourceName?: boolean;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Compose multiple scanners into a single scanner.
|
|
52
|
-
*
|
|
53
|
-
* **Named-scanner array form** (recommended — matches the README examples):
|
|
54
|
-
* ```ts
|
|
55
|
-
* const scanner = composeScanners(
|
|
56
|
-
* [
|
|
57
|
-
* ['zipGuard', createZipBombGuard({ maxEntries: 512, maxCompressionRatio: 12 })],
|
|
58
|
-
* ['heuristics', CommonHeuristicsScanner],
|
|
59
|
-
* ],
|
|
60
|
-
* { parallel: false, stopOn: 'malicious', timeoutMsPerScanner: 5000, tagSourceName: true }
|
|
61
|
-
* );
|
|
62
|
-
* ```
|
|
63
|
-
*
|
|
64
|
-
* **Variadic form** (backward-compatible):
|
|
65
|
-
* ```ts
|
|
66
|
-
* const scanner = composeScanners(scannerA, scannerB, scannerC);
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export declare function composeScanners(namedScanners: NamedScanner[], opts?: ComposeScannerOptions): ScanFn;
|
|
70
|
-
export declare function composeScanners(...scanners: Scanner[]): ScanFn;
|
|
71
|
-
export declare function createPresetScanner(preset: PresetName, opts?: PresetOptions): Scanner;
|
|
72
|
-
export declare const PRESET_CONFIGS: Record<string, PresetOptions>;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pompelmi Quarantine Module
|
|
3
|
-
*
|
|
4
|
-
* Provides a first-class quarantine workflow for secure upload pipelines:
|
|
5
|
-
* scan → flag → quarantine → review → promote | delete
|
|
6
|
-
*
|
|
7
|
-
* Entry points:
|
|
8
|
-
* import { QuarantineManager, FilesystemQuarantineStorage } from 'pompelmi/quarantine';
|
|
9
|
-
*
|
|
10
|
-
* The storage layer is pluggable via the `QuarantineStorage` interface.
|
|
11
|
-
* `FilesystemQuarantineStorage` is the reference implementation for local/on-premise use.
|
|
12
|
-
*
|
|
13
|
-
* This module is Node.js-only (uses fs/crypto/path).
|
|
14
|
-
* It is NOT included in the 'pompelmi/browser' or 'pompelmi/react' bundles.
|
|
15
|
-
*/
|
|
16
|
-
export { FilesystemQuarantineStorage, type FilesystemQuarantineStorageOptions, type QuarantineStorage, } from "./storage";
|
|
17
|
-
export type { QuarantineDecision, QuarantinedFileInfo, QuarantineEntry, QuarantineFilter, QuarantineReport, QuarantineReview, QuarantineStatus, } from "./types";
|
|
18
|
-
export { QuarantineManager, type QuarantineManagerOptions } from "./workflow";
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quarantine storage adapter interface and filesystem reference implementation.
|
|
3
|
-
*
|
|
4
|
-
* The `QuarantineStorage` interface decouples the quarantine workflow from any
|
|
5
|
-
* specific persistence layer. You can implement it for S3, GCS, a database,
|
|
6
|
-
* or any other backend.
|
|
7
|
-
*
|
|
8
|
-
* The built-in `FilesystemQuarantineStorage` stores files and metadata as JSON
|
|
9
|
-
* in a local directory — suitable for development, self-hosted, and on-premise
|
|
10
|
-
* deployments where data must not leave the machine.
|
|
11
|
-
*
|
|
12
|
-
* @module quarantine/storage
|
|
13
|
-
*/
|
|
14
|
-
import type { QuarantineEntry, QuarantineFilter } from "./types";
|
|
15
|
-
/**
|
|
16
|
-
* Storage adapter for the quarantine workflow.
|
|
17
|
-
* Implement this interface to support any backend (S3, GCS, DB, etc.).
|
|
18
|
-
*/
|
|
19
|
-
export interface QuarantineStorage {
|
|
20
|
-
/**
|
|
21
|
-
* Persist the raw bytes of a quarantined file.
|
|
22
|
-
* Returns a `storageKey` that can later be used to retrieve or delete the bytes.
|
|
23
|
-
*/
|
|
24
|
-
saveFile(id: string, bytes: Uint8Array): Promise<string>;
|
|
25
|
-
/**
|
|
26
|
-
* Retrieve the raw bytes of a quarantined file.
|
|
27
|
-
* Returns `null` if the file is not found.
|
|
28
|
-
*/
|
|
29
|
-
getFile(storageKey: string): Promise<Uint8Array | null>;
|
|
30
|
-
/**
|
|
31
|
-
* Permanently remove the raw bytes of a quarantined file.
|
|
32
|
-
* No-op if already removed.
|
|
33
|
-
*/
|
|
34
|
-
deleteFile(storageKey: string): Promise<void>;
|
|
35
|
-
/** Persist a quarantine entry (metadata + scan report). */
|
|
36
|
-
saveEntry(entry: QuarantineEntry): Promise<void>;
|
|
37
|
-
/** Load a quarantine entry by id. Returns `null` if not found. */
|
|
38
|
-
getEntry(id: string): Promise<QuarantineEntry | null>;
|
|
39
|
-
/** Update an existing quarantine entry (partial update). */
|
|
40
|
-
updateEntry(id: string, patch: Partial<QuarantineEntry>): Promise<QuarantineEntry>;
|
|
41
|
-
/** List quarantine entries matching the given filter. */
|
|
42
|
-
listEntries(filter?: QuarantineFilter): Promise<QuarantineEntry[]>;
|
|
43
|
-
/** Return the total count of quarantine entries matching the filter. */
|
|
44
|
-
countEntries(filter?: QuarantineFilter): Promise<number>;
|
|
45
|
-
}
|
|
46
|
-
export interface FilesystemQuarantineStorageOptions {
|
|
47
|
-
/**
|
|
48
|
-
* Root directory for quarantine storage.
|
|
49
|
-
* Two subdirectories are created: `files/` (raw bytes) and `meta/` (JSON).
|
|
50
|
-
*/
|
|
51
|
-
dir: string;
|
|
52
|
-
/** Create the directory if it does not exist (default: true). */
|
|
53
|
-
createIfMissing?: boolean;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Reference implementation of `QuarantineStorage` backed by the local filesystem.
|
|
57
|
-
*
|
|
58
|
-
* File layout:
|
|
59
|
-
* <dir>/files/<storageKey> — raw file bytes
|
|
60
|
-
* <dir>/meta/<id>.json — QuarantineEntry JSON
|
|
61
|
-
*
|
|
62
|
-
* Suitable for single-process servers. For multi-process or distributed
|
|
63
|
-
* deployments, implement `QuarantineStorage` against a shared backend.
|
|
64
|
-
*/
|
|
65
|
-
export declare class FilesystemQuarantineStorage implements QuarantineStorage {
|
|
66
|
-
private readonly filesDir;
|
|
67
|
-
private readonly metaDir;
|
|
68
|
-
constructor(options: FilesystemQuarantineStorageOptions);
|
|
69
|
-
saveFile(id: string, bytes: Uint8Array): Promise<string>;
|
|
70
|
-
getFile(storageKey: string): Promise<Uint8Array | null>;
|
|
71
|
-
deleteFile(storageKey: string): Promise<void>;
|
|
72
|
-
saveEntry(entry: QuarantineEntry): Promise<void>;
|
|
73
|
-
getEntry(id: string): Promise<QuarantineEntry | null>;
|
|
74
|
-
updateEntry(id: string, patch: Partial<QuarantineEntry>): Promise<QuarantineEntry>;
|
|
75
|
-
listEntries(filter?: QuarantineFilter): Promise<QuarantineEntry[]>;
|
|
76
|
-
countEntries(filter?: QuarantineFilter): Promise<number>;
|
|
77
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quarantine system types for Pompelmi.
|
|
3
|
-
*
|
|
4
|
-
* A quarantine entry represents a file that was flagged during scanning and is
|
|
5
|
-
* held for manual review before being accepted or permanently removed.
|
|
6
|
-
*
|
|
7
|
-
* The lifecycle of a quarantined entry:
|
|
8
|
-
*
|
|
9
|
-
* scan → flagged → quarantined → reviewed → promoted | deleted
|
|
10
|
-
*
|
|
11
|
-
* @module quarantine/types
|
|
12
|
-
*/
|
|
13
|
-
import type { ScanReport } from "../types";
|
|
14
|
-
/** The review status of a quarantined file. */
|
|
15
|
-
export type QuarantineStatus = "pending" | "reviewing" | "promoted" | "deleted";
|
|
16
|
-
/** Immutable metadata about the file at upload time. */
|
|
17
|
-
export interface QuarantinedFileInfo {
|
|
18
|
-
/** Original filename supplied by the uploader. */
|
|
19
|
-
originalName: string;
|
|
20
|
-
/** Detected MIME type (from magic bytes, not the Content-Type header). */
|
|
21
|
-
mimeType?: string;
|
|
22
|
-
/** File size in bytes. */
|
|
23
|
-
sizeBytes: number;
|
|
24
|
-
/** SHA-256 hex digest of the file content. */
|
|
25
|
-
sha256: string;
|
|
26
|
-
/** Uploader identity — opaque string (user id, session id, IP, etc.). */
|
|
27
|
-
uploadedBy?: string;
|
|
28
|
-
}
|
|
29
|
-
/** A quarantine entry created when a file is flagged. */
|
|
30
|
-
export interface QuarantineEntry {
|
|
31
|
-
/** Stable identifier for this quarantine entry (UUID). */
|
|
32
|
-
id: string;
|
|
33
|
-
/** Filename used to locate the quarantined bytes in storage. */
|
|
34
|
-
storageKey: string;
|
|
35
|
-
/** Metadata captured at upload time. */
|
|
36
|
-
file: QuarantinedFileInfo;
|
|
37
|
-
/** The scan report that triggered quarantine. */
|
|
38
|
-
scanReport: ScanReport;
|
|
39
|
-
/** ISO-8601 timestamp when the file was quarantined. */
|
|
40
|
-
quarantinedAt: string;
|
|
41
|
-
/** Current review status. */
|
|
42
|
-
status: QuarantineStatus;
|
|
43
|
-
/** ISO-8601 timestamp of the last status change. */
|
|
44
|
-
updatedAt: string;
|
|
45
|
-
/** Identity of the reviewer (operator id, etc.). Populated at review time. */
|
|
46
|
-
reviewedBy?: string;
|
|
47
|
-
/** Free-text review note from the operator. */
|
|
48
|
-
reviewNote?: string;
|
|
49
|
-
/** ISO-8601 timestamp when the final decision (promote/delete) was made. */
|
|
50
|
-
resolvedAt?: string;
|
|
51
|
-
/** Optional application-specific tags or labels. */
|
|
52
|
-
tags?: string[];
|
|
53
|
-
}
|
|
54
|
-
/** The outcome of a manual review. */
|
|
55
|
-
export type QuarantineDecision = "promote" | "delete";
|
|
56
|
-
/** Input required to resolve a quarantine entry. */
|
|
57
|
-
export interface QuarantineReview {
|
|
58
|
-
decision: QuarantineDecision;
|
|
59
|
-
reviewedBy?: string;
|
|
60
|
-
reviewNote?: string;
|
|
61
|
-
}
|
|
62
|
-
/** A structured JSON report of all quarantined entries (for audit/export). */
|
|
63
|
-
export interface QuarantineReport {
|
|
64
|
-
generatedAt: string;
|
|
65
|
-
totalEntries: number;
|
|
66
|
-
byStatus: Record<QuarantineStatus, number>;
|
|
67
|
-
entries: QuarantineEntry[];
|
|
68
|
-
}
|
|
69
|
-
/** Filter parameters for listing quarantine entries. */
|
|
70
|
-
export interface QuarantineFilter {
|
|
71
|
-
status?: QuarantineStatus | QuarantineStatus[];
|
|
72
|
-
/** Return only entries quarantined after this ISO-8601 timestamp. */
|
|
73
|
-
after?: string;
|
|
74
|
-
/** Return only entries quarantined before this ISO-8601 timestamp. */
|
|
75
|
-
before?: string;
|
|
76
|
-
/** Maximum number of results to return. */
|
|
77
|
-
limit?: number;
|
|
78
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quarantine workflow — core API for the quarantine/review/resolve lifecycle.
|
|
3
|
-
*
|
|
4
|
-
* Usage (Node.js):
|
|
5
|
-
*
|
|
6
|
-
* ```ts
|
|
7
|
-
* import { scanBytes } from 'pompelmi';
|
|
8
|
-
* import { QuarantineManager, FilesystemQuarantineStorage } from 'pompelmi/quarantine';
|
|
9
|
-
*
|
|
10
|
-
* const quarantine = new QuarantineManager({
|
|
11
|
-
* storage: new FilesystemQuarantineStorage({ dir: './quarantine' }),
|
|
12
|
-
* });
|
|
13
|
-
*
|
|
14
|
-
* const report = await scanBytes(fileBytes, { ctx: { filename: file.name } });
|
|
15
|
-
*
|
|
16
|
-
* if (report.verdict !== 'clean') {
|
|
17
|
-
* const entry = await quarantine.quarantine(fileBytes, report, {
|
|
18
|
-
* originalName: file.name,
|
|
19
|
-
* sizeBytes: fileBytes.length,
|
|
20
|
-
* uploadedBy: req.user?.id,
|
|
21
|
-
* });
|
|
22
|
-
* console.log('Quarantined:', entry.id);
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @module quarantine/workflow
|
|
27
|
-
*/
|
|
28
|
-
import type { ScanReport } from "../types";
|
|
29
|
-
import type { QuarantineStorage } from "./storage";
|
|
30
|
-
import type { QuarantinedFileInfo, QuarantineEntry, QuarantineFilter, QuarantineReport, QuarantineReview } from "./types";
|
|
31
|
-
export interface QuarantineManagerOptions {
|
|
32
|
-
/** Storage adapter — use `FilesystemQuarantineStorage` for local deployments. */
|
|
33
|
-
storage: QuarantineStorage;
|
|
34
|
-
/**
|
|
35
|
-
* If true, files with a 'suspicious' verdict are also quarantined.
|
|
36
|
-
* Default: true.
|
|
37
|
-
*/
|
|
38
|
-
quarantineSuspicious?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* If true, files with a 'malicious' verdict are also quarantined.
|
|
41
|
-
* Default: true.
|
|
42
|
-
*/
|
|
43
|
-
quarantineMalicious?: boolean;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Manages the full lifecycle of quarantined files:
|
|
47
|
-
* scan → quarantine → review → promote | delete
|
|
48
|
-
*/
|
|
49
|
-
export declare class QuarantineManager {
|
|
50
|
-
private readonly storage;
|
|
51
|
-
private readonly quarantineSuspicious;
|
|
52
|
-
private readonly quarantineMalicious;
|
|
53
|
-
constructor(options: QuarantineManagerOptions);
|
|
54
|
-
/**
|
|
55
|
-
* Determine whether a scan report should trigger quarantine per the
|
|
56
|
-
* configured policy.
|
|
57
|
-
*/
|
|
58
|
-
shouldQuarantine(report: ScanReport): boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Quarantine a file: save the bytes in storage, create the metadata entry,
|
|
61
|
-
* and return the entry.
|
|
62
|
-
*
|
|
63
|
-
* @param bytes Raw file bytes.
|
|
64
|
-
* @param report The scan report that triggered quarantine.
|
|
65
|
-
* @param fileInfo Partial metadata; `sha256` is derived from `bytes` if omitted.
|
|
66
|
-
*/
|
|
67
|
-
quarantine(bytes: Uint8Array, report: ScanReport, fileInfo: Omit<QuarantinedFileInfo, "sha256"> & {
|
|
68
|
-
sha256?: string;
|
|
69
|
-
}): Promise<QuarantineEntry>;
|
|
70
|
-
/**
|
|
71
|
-
* Mark an entry as being actively reviewed.
|
|
72
|
-
*/
|
|
73
|
-
startReview(id: string, reviewedBy?: string): Promise<QuarantineEntry>;
|
|
74
|
-
/**
|
|
75
|
-
* Resolve a quarantine entry with a final decision.
|
|
76
|
-
*
|
|
77
|
-
* - `promote`: the file is cleared — bytes remain in storage for the caller
|
|
78
|
-
* to move to its final destination.
|
|
79
|
-
* - `delete`: the bytes are permanently removed from quarantine storage.
|
|
80
|
-
*/
|
|
81
|
-
resolve(id: string, review: QuarantineReview): Promise<QuarantineEntry>;
|
|
82
|
-
/**
|
|
83
|
-
* Retrieve the raw bytes of a promoted file so the caller can move it to
|
|
84
|
-
* permanent storage. Returns `null` if the entry is not found or has been
|
|
85
|
-
* deleted.
|
|
86
|
-
*/
|
|
87
|
-
getFile(id: string): Promise<Uint8Array | null>;
|
|
88
|
-
getEntry(id: string): Promise<QuarantineEntry | null>;
|
|
89
|
-
listEntries(filter?: QuarantineFilter): Promise<QuarantineEntry[]>;
|
|
90
|
-
listPending(): Promise<QuarantineEntry[]>;
|
|
91
|
-
countEntries(filter?: QuarantineFilter): Promise<number>;
|
|
92
|
-
/**
|
|
93
|
-
* Generate a structured JSON report of all quarantine entries matching the
|
|
94
|
-
* filter — suitable for audit logs and dashboards.
|
|
95
|
-
*/
|
|
96
|
-
report(filter?: QuarantineFilter): Promise<QuarantineReport>;
|
|
97
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/react-index.ts — React entry point for Pompelmi.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the full browser-safe Pompelmi API plus the React hook.
|
|
5
|
-
* Import from 'pompelmi/react'.
|
|
6
|
-
*
|
|
7
|
-
* Peer dependency: react ^18 || ^19
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* import { useFileScanner } from 'pompelmi/react';
|
|
11
|
-
*/
|
|
12
|
-
export * from "./browser-index";
|
|
13
|
-
export { useFileScanner } from "./useFileScanner";
|
package/dist/types/src/risk.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export type Severity = "clean" | "suspicious" | "malicious";
|
|
2
|
-
export type Match = {
|
|
3
|
-
rule: string;
|
|
4
|
-
meta?: Record<string, any>;
|
|
5
|
-
};
|
|
6
|
-
export type Verdict = {
|
|
7
|
-
severity: Severity;
|
|
8
|
-
reasons: string[];
|
|
9
|
-
matches: Match[];
|
|
10
|
-
mime?: string;
|
|
11
|
-
};
|
|
12
|
-
export type Policy = {
|
|
13
|
-
includeExtensions: string[];
|
|
14
|
-
allowedMimeTypes: string[];
|
|
15
|
-
maxFileSizeBytes: number;
|
|
16
|
-
denyScriptableSvg?: boolean;
|
|
17
|
-
};
|
|
18
|
-
export declare function prefilter(bytes: Uint8Array, origName: string, policy: Policy): Verdict;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { YaraMatch } from "../yara/index";
|
|
2
|
-
import type { RemoteEngineOptions } from "../yara/remote";
|
|
3
|
-
export interface RemoteScanResult {
|
|
4
|
-
file: File;
|
|
5
|
-
matches: YaraMatch[];
|
|
6
|
-
error?: string;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Scansiona una lista di File nel browser usando il motore remoto via HTTP.
|
|
10
|
-
* Non richiede WASM né dipendenze native sul client.
|
|
11
|
-
*/
|
|
12
|
-
export declare function scanFilesWithRemoteYara(files: File[], rulesSource: string, remote: RemoteEngineOptions): Promise<RemoteScanResult[]>;
|