@mlvscan/wasm-core 1.1.7
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 +19 -0
- package/dist/_framework/MLVScan.Core.wasm +0 -0
- package/dist/_framework/MLVScan.WASM.wasm +0 -0
- package/dist/_framework/Mono.Cecil.wasm +0 -0
- package/dist/_framework/System.Collections.Concurrent.wasm +0 -0
- package/dist/_framework/System.Collections.wasm +0 -0
- package/dist/_framework/System.IO.Compression.wasm +0 -0
- package/dist/_framework/System.Linq.wasm +0 -0
- package/dist/_framework/System.Memory.wasm +0 -0
- package/dist/_framework/System.Private.CoreLib.wasm +0 -0
- package/dist/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
- package/dist/_framework/System.Security.Cryptography.wasm +0 -0
- package/dist/_framework/System.Text.Encodings.Web.wasm +0 -0
- package/dist/_framework/System.Text.Json.wasm +0 -0
- package/dist/_framework/System.Text.RegularExpressions.wasm +0 -0
- package/dist/_framework/blazor.boot.json +46 -0
- package/dist/_framework/dotnet.js +4 -0
- package/dist/_framework/dotnet.js.map +1 -0
- package/dist/_framework/dotnet.native.js +17 -0
- package/dist/_framework/dotnet.native.js.symbols +7909 -0
- package/dist/_framework/dotnet.native.wasm +0 -0
- package/dist/_framework/dotnet.runtime.js +4 -0
- package/dist/_framework/dotnet.runtime.js.map +1 -0
- package/dist/_framework/icudt_CJK.dat +0 -0
- package/dist/_framework/icudt_EFIGS.dat +0 -0
- package/dist/_framework/icudt_no_CJK.dat +0 -0
- package/dist/_framework/supportFiles/0_runtimeconfig.bin +1 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +242 -0
- package/dist/types.d.ts +121 -0
- package/dist/types.js +7 -0
- package/package.json +21 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MMicrosoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmabilitytruefSystem.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerializationfalse'System.Diagnostics.Debugger.IsSupportedfalse,System.Diagnostics.Metrics.Meter.IsSupportedfalse2System.Diagnostics.Tracing.EventSource.IsSupportedfalseSystem.Globalization.InvariantfalseSystem.TimeZoneInfo.Invariantfalse&System.Linq.Enumerable.IsSizeOptimizedtrue)System.Net.Http.EnableActivityPropagationfalse+System.Net.Http.WasmEnableStreamingResponsetrue*System.Net.SocketsHttpHandler.Http3Supportfalse6System.Reflection.Metadata.MetadataUpdater.IsSupportedfalse9System.Resources.ResourceManager.AllowCustomResourceTypesfalse&System.Resources.UseSystemResourceKeystrue<System.Runtime.InteropServices.BuiltInComInterop.IsSupportedfalseJSystem.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHostingfalse9System.Runtime.InteropServices.EnableCppCLIHostActivationfalseVSystem.Runtime.InteropServices.Marshalling.EnableGeneratedComInterfaceComImportInteropfalseESystem.Runtime.Serialization.EnableUnsafeBinaryFormatterSerializationfalse&System.StartupHookProvider.IsSupportedfalse-System.Text.Encoding.EnableUnsafeUTF7Encodingfalse<System.Text.Json.JsonSerializer.IsReflectionEnabledByDefaultfalse-System.Threading.Thread.EnableAutoreleasePoolfalse
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* WebAssembly core for MLVScan. Loads the .NET WASM runtime and MLVScan.WASM assembly
|
|
5
|
+
* to scan Unity mod assemblies (e.g. MelonLoader/BepInEx DLLs) in the browser.
|
|
6
|
+
*
|
|
7
|
+
* Call {@link initScanner} before scanning (or let {@link scanAssembly} init automatically).
|
|
8
|
+
* Use {@link getScannerStatus} or {@link getInitError} to detect mock fallback and show
|
|
9
|
+
* appropriate UI. Use {@link isMockScanner} to distinguish "running in mock mode" from
|
|
10
|
+
* "real WASM scanner ready".
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { initScanner, scanAssembly, getScannerStatus } from '@mlvscan/wasm-core'
|
|
15
|
+
* await initScanner({ baseUrl: '/' })
|
|
16
|
+
* const status = getScannerStatus()
|
|
17
|
+
* if (status.initError) console.warn('Scanner unavailable:', status.initError)
|
|
18
|
+
* const result = await scanAssembly(dllBytes, 'MyMod.dll')
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import type { ScanResult } from './types';
|
|
22
|
+
/**
|
|
23
|
+
* Options for initializing the WASM scanner.
|
|
24
|
+
*
|
|
25
|
+
* Pass these to {@link initScanner}. The scanner loads `_framework/dotnet.js` from
|
|
26
|
+
* `baseUrl`; ensure your dev server or build serves the npm package's `dist/_framework`
|
|
27
|
+
* at that path.
|
|
28
|
+
*/
|
|
29
|
+
export interface ScannerInitOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Base URL where the _framework directory is served.
|
|
32
|
+
* Defaults to '/'.
|
|
33
|
+
*/
|
|
34
|
+
baseUrl?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether to use the mock scanner (useful for testing or if WASM fails).
|
|
37
|
+
* Defaults to false.
|
|
38
|
+
*/
|
|
39
|
+
useMock?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* If true, initScanner() throws when WASM fails to load or initialize
|
|
42
|
+
* (instead of falling back to mock). Use when you want to show an error UI
|
|
43
|
+
* rather than silent mock. Ignored when useMock is true.
|
|
44
|
+
* Defaults to false.
|
|
45
|
+
*/
|
|
46
|
+
throwOnInitFailure?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Snapshot of scanner state after init. Use with {@link getScannerStatus} to drive UI
|
|
50
|
+
* (e.g. show "Scanner unavailable" when `initError` is set, or "Mock mode" when
|
|
51
|
+
* `isMock && mockRequestedExplicitly`).
|
|
52
|
+
*/
|
|
53
|
+
export interface ScannerStatus {
|
|
54
|
+
/** True when init has completed (success or fallback). */
|
|
55
|
+
ready: boolean;
|
|
56
|
+
/** True when running in mock mode (explicit or fallback). */
|
|
57
|
+
isMock: boolean;
|
|
58
|
+
/** True when mock was requested via init options; false when fallback due to error. */
|
|
59
|
+
mockRequestedExplicitly: boolean;
|
|
60
|
+
/** Set when we fell back to mock due to load/init failure. Null if real WASM is active or mock was explicit. */
|
|
61
|
+
initError: Error | null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Initializes the WASM scanner: loads the .NET runtime and MLVScan.WASM assembly.
|
|
65
|
+
* Call once before scanning (or rely on {@link scanAssembly} / {@link getScannerVersion}
|
|
66
|
+
* to init on first use). Safe to call multiple times; subsequent calls no-op if already
|
|
67
|
+
* initialized.
|
|
68
|
+
*
|
|
69
|
+
* @param options - See {@link ScannerInitOptions}. Omitted options use defaults.
|
|
70
|
+
* @throws When `throwOnInitFailure` is true and WASM fails to load or initialize.
|
|
71
|
+
*/
|
|
72
|
+
export declare function initScanner(options?: ScannerInitOptions): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Scans a .NET assembly (e.g. a Unity mod DLL) and returns structured findings.
|
|
75
|
+
* Initializes the scanner if not yet initialized. In mock mode returns a result
|
|
76
|
+
* with zero findings and scanner version `1.0.0-mock`.
|
|
77
|
+
*
|
|
78
|
+
* @param fileBytes - Raw bytes of the assembly (e.g. from FileReader or fetch).
|
|
79
|
+
* @param fileName - Name of the file (used in the result and for logging).
|
|
80
|
+
* @returns A {@link ScanResult} with metadata, summary, and findings.
|
|
81
|
+
* @throws When the scanner is not in mock mode but the WASM scan call fails.
|
|
82
|
+
*/
|
|
83
|
+
export declare function scanAssembly(fileBytes: Uint8Array, fileName: string): Promise<ScanResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Returns whether the scanner is ready to use (initialization finished, either
|
|
86
|
+
* with real WASM or mock). Use this to gate UI (e.g. enable "Scan" only when
|
|
87
|
+
* ready). For more detail use {@link getScannerStatus}.
|
|
88
|
+
*/
|
|
89
|
+
export declare function isScannerReady(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Returns true when the scanner is running in mock mode (either requested via
|
|
92
|
+
* init options or fallback due to WASM load/init failure). Use to show a
|
|
93
|
+
* "Mock mode" badge or to avoid relying on real scan results.
|
|
94
|
+
*/
|
|
95
|
+
export declare function isMockScanner(): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Returns the error that caused fallback to mock, or null if WASM is active
|
|
98
|
+
* or mock was explicitly requested. Use with {@link getScannerStatus} to show
|
|
99
|
+
* "Scanner unavailable: {message}".
|
|
100
|
+
*/
|
|
101
|
+
export declare function getInitError(): Error | null;
|
|
102
|
+
/**
|
|
103
|
+
* Returns the current scanner status: ready flag, mock mode, whether mock was
|
|
104
|
+
* explicit, and any init error. Use to drive UI (e.g. banner when
|
|
105
|
+
* `status.initError`, or "Mock mode" when `status.isMock`).
|
|
106
|
+
*/
|
|
107
|
+
export declare function getScannerStatus(): ScannerStatus;
|
|
108
|
+
/**
|
|
109
|
+
* Returns the scanner engine version (e.g. `"1.1.7"`). In mock mode returns
|
|
110
|
+
* `"1.0.0-mock"`. Initializes the scanner if not yet initialized.
|
|
111
|
+
*
|
|
112
|
+
* @throws When the real WASM is loaded but the version call fails.
|
|
113
|
+
*/
|
|
114
|
+
export declare function getScannerVersion(): Promise<string>;
|
|
115
|
+
/**
|
|
116
|
+
* Returns the scan result schema version (e.g. `"1.0.0"`). In mock mode returns
|
|
117
|
+
* `"1.0.0"`. Initializes the scanner if not yet initialized.
|
|
118
|
+
*
|
|
119
|
+
* @throws When the real WASM is loaded but the schema version call fails.
|
|
120
|
+
*/
|
|
121
|
+
export declare function getSchemaVersion(): Promise<string>;
|
|
122
|
+
/** Re-export scan result and finding types. */
|
|
123
|
+
export * from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* WebAssembly core for MLVScan. Loads the .NET WASM runtime and MLVScan.WASM assembly
|
|
5
|
+
* to scan Unity mod assemblies (e.g. MelonLoader/BepInEx DLLs) in the browser.
|
|
6
|
+
*
|
|
7
|
+
* Call {@link initScanner} before scanning (or let {@link scanAssembly} init automatically).
|
|
8
|
+
* Use {@link getScannerStatus} or {@link getInitError} to detect mock fallback and show
|
|
9
|
+
* appropriate UI. Use {@link isMockScanner} to distinguish "running in mock mode" from
|
|
10
|
+
* "real WASM scanner ready".
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { initScanner, scanAssembly, getScannerStatus } from '@mlvscan/wasm-core'
|
|
15
|
+
* await initScanner({ baseUrl: '/' })
|
|
16
|
+
* const status = getScannerStatus()
|
|
17
|
+
* if (status.initError) console.warn('Scanner unavailable:', status.initError)
|
|
18
|
+
* const result = await scanAssembly(dllBytes, 'MyMod.dll')
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
let scannerExports = null;
|
|
22
|
+
let scannerLoaded = false;
|
|
23
|
+
let dotnetModule = null;
|
|
24
|
+
let useMockScanner = false;
|
|
25
|
+
/** Set when we fell back to mock due to load/init failure (not when useMock: true). */
|
|
26
|
+
let initError = null;
|
|
27
|
+
/** True when mock was explicitly requested via options; false when fallback due to error. */
|
|
28
|
+
let mockRequestedExplicitly = false;
|
|
29
|
+
const mockScanResult = {
|
|
30
|
+
schemaVersion: '1.0.0',
|
|
31
|
+
metadata: {
|
|
32
|
+
scannerVersion: '1.0.0-mock',
|
|
33
|
+
timestamp: new Date().toISOString(),
|
|
34
|
+
scanMode: 'summary',
|
|
35
|
+
platform: 'wasm',
|
|
36
|
+
},
|
|
37
|
+
input: {
|
|
38
|
+
fileName: 'sample.dll',
|
|
39
|
+
sizeBytes: 1024,
|
|
40
|
+
},
|
|
41
|
+
summary: {
|
|
42
|
+
totalFindings: 0,
|
|
43
|
+
countBySeverity: {},
|
|
44
|
+
triggeredRules: [],
|
|
45
|
+
},
|
|
46
|
+
findings: []
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Loads the .NET WASM runtime from the given base URL. Caches the module and sets
|
|
50
|
+
* initError / useMockScanner on failure.
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
async function loadDotnet(baseUrl) {
|
|
54
|
+
if (dotnetModule) {
|
|
55
|
+
return dotnetModule;
|
|
56
|
+
}
|
|
57
|
+
// Ensure trailing slash
|
|
58
|
+
const safeBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
59
|
+
const dotnetUrl = `${safeBaseUrl}_framework/dotnet.js`;
|
|
60
|
+
try {
|
|
61
|
+
// Dynamic import to bypass some bundlers
|
|
62
|
+
const dynamicImport = new Function('url', 'return import(url)');
|
|
63
|
+
const mod = await dynamicImport(dotnetUrl);
|
|
64
|
+
dotnetModule = mod.dotnet || mod.default || mod;
|
|
65
|
+
return dotnetModule;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
initError = err instanceof Error ? err : new Error(String(err));
|
|
69
|
+
console.warn('Blazor WASM not available, using mock scanner', initError);
|
|
70
|
+
useMockScanner = true;
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Initializes the WASM scanner: loads the .NET runtime and MLVScan.WASM assembly.
|
|
76
|
+
* Call once before scanning (or rely on {@link scanAssembly} / {@link getScannerVersion}
|
|
77
|
+
* to init on first use). Safe to call multiple times; subsequent calls no-op if already
|
|
78
|
+
* initialized.
|
|
79
|
+
*
|
|
80
|
+
* @param options - See {@link ScannerInitOptions}. Omitted options use defaults.
|
|
81
|
+
* @throws When `throwOnInitFailure` is true and WASM fails to load or initialize.
|
|
82
|
+
*/
|
|
83
|
+
export async function initScanner(options = {}) {
|
|
84
|
+
if (scannerLoaded && scannerExports) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const { baseUrl = '/', useMock = false, throwOnInitFailure = false } = options;
|
|
88
|
+
if (useMock) {
|
|
89
|
+
initError = null;
|
|
90
|
+
mockRequestedExplicitly = true;
|
|
91
|
+
useMockScanner = true;
|
|
92
|
+
scannerExports = null;
|
|
93
|
+
scannerLoaded = true;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
initError = null;
|
|
97
|
+
mockRequestedExplicitly = false;
|
|
98
|
+
try {
|
|
99
|
+
const dotnet = await loadDotnet(baseUrl);
|
|
100
|
+
if (useMockScanner || !dotnet) {
|
|
101
|
+
scannerExports = null;
|
|
102
|
+
scannerLoaded = true;
|
|
103
|
+
if (throwOnInitFailure && initError) {
|
|
104
|
+
throw initError;
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const safeBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
109
|
+
const frameworkPath = `${safeBaseUrl}_framework/`;
|
|
110
|
+
const { getAssemblyExports, getConfig } = await dotnet
|
|
111
|
+
.withDiagnosticTracing(false)
|
|
112
|
+
.create({
|
|
113
|
+
locateFile: (path) => frameworkPath + path,
|
|
114
|
+
});
|
|
115
|
+
scannerExports = await getAssemblyExports(getConfig().mainAssemblyName);
|
|
116
|
+
scannerLoaded = true;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
120
|
+
initError = err;
|
|
121
|
+
console.warn('Failed to initialize WASM scanner, falling back to mock:', err);
|
|
122
|
+
useMockScanner = true;
|
|
123
|
+
scannerExports = null;
|
|
124
|
+
scannerLoaded = true;
|
|
125
|
+
if (throwOnInitFailure) {
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Scans a .NET assembly (e.g. a Unity mod DLL) and returns structured findings.
|
|
132
|
+
* Initializes the scanner if not yet initialized. In mock mode returns a result
|
|
133
|
+
* with zero findings and scanner version `1.0.0-mock`.
|
|
134
|
+
*
|
|
135
|
+
* @param fileBytes - Raw bytes of the assembly (e.g. from FileReader or fetch).
|
|
136
|
+
* @param fileName - Name of the file (used in the result and for logging).
|
|
137
|
+
* @returns A {@link ScanResult} with metadata, summary, and findings.
|
|
138
|
+
* @throws When the scanner is not in mock mode but the WASM scan call fails.
|
|
139
|
+
*/
|
|
140
|
+
export async function scanAssembly(fileBytes, fileName) {
|
|
141
|
+
if (!scannerLoaded) {
|
|
142
|
+
await initScanner();
|
|
143
|
+
}
|
|
144
|
+
if (useMockScanner || !scannerExports) {
|
|
145
|
+
return {
|
|
146
|
+
...mockScanResult,
|
|
147
|
+
input: {
|
|
148
|
+
fileName,
|
|
149
|
+
sizeBytes: fileBytes.length,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (!scannerExports.MLVScan?.WASM?.ScannerExports) {
|
|
154
|
+
throw new Error('Scanner not properly initialized: MLVScan.WASM.ScannerExports not found');
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const resultJson = scannerExports.MLVScan.WASM.ScannerExports.ScanAssembly(fileBytes, fileName);
|
|
158
|
+
return JSON.parse(resultJson);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
throw new Error(`Scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Returns whether the scanner is ready to use (initialization finished, either
|
|
166
|
+
* with real WASM or mock). Use this to gate UI (e.g. enable "Scan" only when
|
|
167
|
+
* ready). For more detail use {@link getScannerStatus}.
|
|
168
|
+
*/
|
|
169
|
+
export function isScannerReady() {
|
|
170
|
+
return scannerLoaded && (useMockScanner || scannerExports !== null);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns true when the scanner is running in mock mode (either requested via
|
|
174
|
+
* init options or fallback due to WASM load/init failure). Use to show a
|
|
175
|
+
* "Mock mode" badge or to avoid relying on real scan results.
|
|
176
|
+
*/
|
|
177
|
+
export function isMockScanner() {
|
|
178
|
+
return useMockScanner;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Returns the error that caused fallback to mock, or null if WASM is active
|
|
182
|
+
* or mock was explicitly requested. Use with {@link getScannerStatus} to show
|
|
183
|
+
* "Scanner unavailable: {message}".
|
|
184
|
+
*/
|
|
185
|
+
export function getInitError() {
|
|
186
|
+
return initError;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Returns the current scanner status: ready flag, mock mode, whether mock was
|
|
190
|
+
* explicit, and any init error. Use to drive UI (e.g. banner when
|
|
191
|
+
* `status.initError`, or "Mock mode" when `status.isMock`).
|
|
192
|
+
*/
|
|
193
|
+
export function getScannerStatus() {
|
|
194
|
+
return {
|
|
195
|
+
ready: scannerLoaded && (useMockScanner || scannerExports !== null),
|
|
196
|
+
isMock: useMockScanner,
|
|
197
|
+
mockRequestedExplicitly,
|
|
198
|
+
initError,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Returns the scanner engine version (e.g. `"1.1.7"`). In mock mode returns
|
|
203
|
+
* `"1.0.0-mock"`. Initializes the scanner if not yet initialized.
|
|
204
|
+
*
|
|
205
|
+
* @throws When the real WASM is loaded but the version call fails.
|
|
206
|
+
*/
|
|
207
|
+
export async function getScannerVersion() {
|
|
208
|
+
if (!scannerLoaded) {
|
|
209
|
+
await initScanner();
|
|
210
|
+
}
|
|
211
|
+
if (useMockScanner || !scannerExports?.MLVScan?.WASM?.ScannerExports) {
|
|
212
|
+
return '1.0.0-mock';
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
return scannerExports.MLVScan.WASM.ScannerExports.GetVersion();
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw new Error(`Failed to get scanner version: ${error instanceof Error ? error.message : String(error)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Returns the scan result schema version (e.g. `"1.0.0"`). In mock mode returns
|
|
223
|
+
* `"1.0.0"`. Initializes the scanner if not yet initialized.
|
|
224
|
+
*
|
|
225
|
+
* @throws When the real WASM is loaded but the schema version call fails.
|
|
226
|
+
*/
|
|
227
|
+
export async function getSchemaVersion() {
|
|
228
|
+
if (!scannerLoaded) {
|
|
229
|
+
await initScanner();
|
|
230
|
+
}
|
|
231
|
+
if (useMockScanner || !scannerExports?.MLVScan?.WASM?.ScannerExports) {
|
|
232
|
+
return '1.0.0';
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
return scannerExports.MLVScan.WASM.ScannerExports.GetSchemaVersion();
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
throw new Error(`Failed to get schema version: ${error instanceof Error ? error.message : String(error)}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Re-export scan result and finding types. */
|
|
242
|
+
export * from './types.js';
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MLVScan scan result and finding types.
|
|
3
|
+
*
|
|
4
|
+
* These match the JSON schema produced by MLVScan.WASM. Use with {@link scanAssembly}
|
|
5
|
+
* from the main package.
|
|
6
|
+
*/
|
|
7
|
+
/** Root object returned by a scan. Contains metadata, input info, summary, and findings. */
|
|
8
|
+
export interface ScanResult {
|
|
9
|
+
/** Schema version of this result (e.g. "1.0.0"). */
|
|
10
|
+
schemaVersion: string;
|
|
11
|
+
/** Scanner and scan run metadata. */
|
|
12
|
+
metadata: ScanMetadata;
|
|
13
|
+
/** The assembly that was scanned. */
|
|
14
|
+
input: ScanInput;
|
|
15
|
+
/** Aggregated counts and triggered rules. */
|
|
16
|
+
summary: ScanSummary;
|
|
17
|
+
/** Individual security/relevance findings. */
|
|
18
|
+
findings: Finding[];
|
|
19
|
+
/** Optional call chains for detailed mode. */
|
|
20
|
+
callChains?: CallChain[];
|
|
21
|
+
/** Optional data flow chains for developer mode. */
|
|
22
|
+
dataFlows?: DataFlowChain[];
|
|
23
|
+
/** Optional remediation guidance for developer mode. */
|
|
24
|
+
developerGuidance?: DeveloperGuidance[];
|
|
25
|
+
}
|
|
26
|
+
/** Metadata about the scanner and this scan run. */
|
|
27
|
+
export interface ScanMetadata {
|
|
28
|
+
scannerVersion: string;
|
|
29
|
+
/** ISO 8601 timestamp of the scan. */
|
|
30
|
+
timestamp: string;
|
|
31
|
+
/** Level of detail: summary, detailed (with call chains), or developer (with data flows and guidance). */
|
|
32
|
+
scanMode: 'summary' | 'detailed' | 'developer';
|
|
33
|
+
/** Where the scan ran: wasm, cli, server, or desktop. */
|
|
34
|
+
platform: 'wasm' | 'cli' | 'server' | 'desktop';
|
|
35
|
+
}
|
|
36
|
+
/** Describes the assembly that was scanned. */
|
|
37
|
+
export interface ScanInput {
|
|
38
|
+
fileName: string;
|
|
39
|
+
sizeBytes: number;
|
|
40
|
+
/** SHA-256 hash of the file when available. */
|
|
41
|
+
sha256Hash?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Aggregated scan summary: total findings and counts by severity. */
|
|
44
|
+
export interface ScanSummary {
|
|
45
|
+
totalFindings: number;
|
|
46
|
+
/** Map of severity (e.g. "Low", "Critical") to count. */
|
|
47
|
+
countBySeverity: Record<string, number>;
|
|
48
|
+
/** Rule IDs that produced at least one finding. */
|
|
49
|
+
triggeredRules: string[];
|
|
50
|
+
}
|
|
51
|
+
/** Finding severity level. */
|
|
52
|
+
export type Severity = 'Low' | 'Medium' | 'High' | 'Critical';
|
|
53
|
+
/** A single finding: one triggered rule or suspicious pattern in the assembly. */
|
|
54
|
+
export interface Finding {
|
|
55
|
+
id?: string;
|
|
56
|
+
ruleId?: string;
|
|
57
|
+
description: string;
|
|
58
|
+
severity: Severity;
|
|
59
|
+
/** Human-readable location (e.g. type/method name or file:line). */
|
|
60
|
+
location: string;
|
|
61
|
+
codeSnippet?: string;
|
|
62
|
+
/** Present in detailed/developer mode when a call chain was analyzed. */
|
|
63
|
+
callChain?: CallChain;
|
|
64
|
+
/** Present in developer mode when a data flow was analyzed. */
|
|
65
|
+
dataFlowChain?: DataFlowChain;
|
|
66
|
+
}
|
|
67
|
+
/** A call chain from entry point to a suspicious declaration. */
|
|
68
|
+
export interface CallChain {
|
|
69
|
+
id?: string;
|
|
70
|
+
ruleId?: string;
|
|
71
|
+
description: string;
|
|
72
|
+
severity: Severity;
|
|
73
|
+
nodes: CallChainNode[];
|
|
74
|
+
}
|
|
75
|
+
/** Role of a node in a call chain. */
|
|
76
|
+
export type CallChainNodeType = 'EntryPoint' | 'IntermediateCall' | 'SuspiciousDeclaration';
|
|
77
|
+
/** One node in a call chain (method or declaration). */
|
|
78
|
+
export interface CallChainNode {
|
|
79
|
+
nodeType: CallChainNodeType;
|
|
80
|
+
location: string;
|
|
81
|
+
description: string;
|
|
82
|
+
codeSnippet?: string;
|
|
83
|
+
}
|
|
84
|
+
/** A data flow from source to sink (e.g. download and execute). */
|
|
85
|
+
export interface DataFlowChain {
|
|
86
|
+
id?: string;
|
|
87
|
+
description: string;
|
|
88
|
+
severity: Severity;
|
|
89
|
+
pattern: DataFlowPattern;
|
|
90
|
+
/** Confidence score (e.g. 0–1). */
|
|
91
|
+
confidence: number;
|
|
92
|
+
sourceVariable?: string;
|
|
93
|
+
methodLocation?: string;
|
|
94
|
+
isCrossMethod: boolean;
|
|
95
|
+
involvedMethods?: string[];
|
|
96
|
+
nodes: DataFlowNode[];
|
|
97
|
+
}
|
|
98
|
+
/** Class of data flow pattern the chain represents. */
|
|
99
|
+
export type DataFlowPattern = 'Legitimate' | 'DownloadAndExecute' | 'DataExfiltration' | 'DynamicCodeLoading' | 'CredentialTheft' | 'RemoteConfigLoad' | 'ObfuscatedPersistence' | 'Unknown';
|
|
100
|
+
/** Role of a node in a data flow (source, transform, sink, or intermediate). */
|
|
101
|
+
export type DataFlowNodeType = 'Source' | 'Transform' | 'Sink' | 'Intermediate';
|
|
102
|
+
/** One node in a data flow chain. */
|
|
103
|
+
export interface DataFlowNode {
|
|
104
|
+
nodeType: DataFlowNodeType;
|
|
105
|
+
location: string;
|
|
106
|
+
operation: string;
|
|
107
|
+
dataDescription: string;
|
|
108
|
+
instructionOffset: number;
|
|
109
|
+
methodKey?: string;
|
|
110
|
+
isMethodBoundary: boolean;
|
|
111
|
+
targetMethodKey?: string;
|
|
112
|
+
codeSnippet?: string;
|
|
113
|
+
}
|
|
114
|
+
/** Remediation suggestion for a rule or finding (developer mode). */
|
|
115
|
+
export interface DeveloperGuidance {
|
|
116
|
+
ruleId?: string;
|
|
117
|
+
remediation: string;
|
|
118
|
+
documentationUrl?: string;
|
|
119
|
+
alternativeApis?: string[];
|
|
120
|
+
isRemediable: boolean;
|
|
121
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mlvscan/wasm-core",
|
|
3
|
+
"version": "1.1.7",
|
|
4
|
+
"description": "WebAssembly core for MLVScan - scanning Unity mods in the browser",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"copy:framework": "node scripts/copy-framework.cjs"
|
|
14
|
+
},
|
|
15
|
+
"author": "Bars",
|
|
16
|
+
"license": "GPL-3.0-or-later",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.0.0",
|
|
19
|
+
"@types/node": "^18.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|