omitly-mcp 0.0.0 → 0.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/LICENSE +34 -0
- package/README.md +205 -0
- package/THIRD-PARTY-NOTICES.md +2214 -0
- package/dist/index.js +582 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.js +77 -0
- package/dist/paths.js.map +1 -0
- package/package.json +51 -4
- package/skill/SKILL.md +63 -0
- package/wasm/leakcheck_wasm.d.ts +26 -0
- package/wasm/leakcheck_wasm.js +232 -0
- package/wasm/leakcheck_wasm_bg.wasm +0 -0
- package/wasm/leakcheck_wasm_bg.wasm.d.ts +11 -0
- package/wasm/package.json +12 -0
package/dist/paths.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem confinement for the MCP surface (threat-model prerequisite).
|
|
3
|
+
*
|
|
4
|
+
* Every path in a tool call comes from the MODEL, so an uncontained server is
|
|
5
|
+
* an arbitrary-read/-write primitive for whatever the model was talked into.
|
|
6
|
+
* All reads and writes are confined to one allowed root:
|
|
7
|
+
*
|
|
8
|
+
* OMITLY_ALLOWED_DIR — explicit root (recommended in the MCP config)
|
|
9
|
+
* otherwise — the directory the server was started in
|
|
10
|
+
*
|
|
11
|
+
* Checks resolve symlinks (realpath) before comparing, so a link inside the
|
|
12
|
+
* root that points outside it is rejected, and outputs must not clobber
|
|
13
|
+
* existing files — the model is told to pick a fresh name instead. These are
|
|
14
|
+
* guardrails against confused-deputy mistakes, not a sandbox for a hostile
|
|
15
|
+
* local user (they own the machine; see docs/THREAT-MODEL.md).
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
/** The confinement root, resolved once at startup. */
|
|
20
|
+
export function allowedRoot() {
|
|
21
|
+
const configured = process.env.OMITLY_ALLOWED_DIR?.trim();
|
|
22
|
+
const root = configured || process.cwd();
|
|
23
|
+
try {
|
|
24
|
+
return realpathSync(root);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new Error(`OMITLY_ALLOWED_DIR does not exist or is unreadable: ${root}. ` +
|
|
28
|
+
`Point it at the directory the agent may read/write PDFs in.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function within(root, target) {
|
|
32
|
+
const rel = path.relative(root, target);
|
|
33
|
+
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
34
|
+
}
|
|
35
|
+
function refusal(what, p, root) {
|
|
36
|
+
return new Error(`${what} "${p}" is outside the allowed directory (${root}). ` +
|
|
37
|
+
`This server only touches files under that directory; ` +
|
|
38
|
+
`set OMITLY_ALLOWED_DIR in the MCP config to change it.`);
|
|
39
|
+
}
|
|
40
|
+
/** Validate a model-supplied INPUT path: must exist inside the root (after
|
|
41
|
+
* symlink resolution). Returns the resolved real path to hand to the engine. */
|
|
42
|
+
export function confineInput(p, root) {
|
|
43
|
+
let real;
|
|
44
|
+
try {
|
|
45
|
+
real = realpathSync(path.resolve(root, p));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new Error(`input file not found: ${p}`);
|
|
49
|
+
}
|
|
50
|
+
if (!within(root, real))
|
|
51
|
+
throw refusal("input path", p, root);
|
|
52
|
+
return real;
|
|
53
|
+
}
|
|
54
|
+
/** Validate a model-supplied OUTPUT path: its parent must exist inside the
|
|
55
|
+
* root, and neither the file nor its `.audit.json` sidecar may already exist
|
|
56
|
+
* (never silently overwrite — ask the model to pick a fresh name). Returns
|
|
57
|
+
* the resolved path to hand to the engine. */
|
|
58
|
+
export function confineOutput(p, root) {
|
|
59
|
+
const resolved = path.resolve(root, p);
|
|
60
|
+
let parent;
|
|
61
|
+
try {
|
|
62
|
+
parent = realpathSync(path.dirname(resolved));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new Error(`output directory not found: ${path.dirname(p)}`);
|
|
66
|
+
}
|
|
67
|
+
const real = path.join(parent, path.basename(resolved));
|
|
68
|
+
if (!within(root, real))
|
|
69
|
+
throw refusal("output path", p, root);
|
|
70
|
+
for (const candidate of [real, `${real}.audit.json`]) {
|
|
71
|
+
if (existsSync(candidate)) {
|
|
72
|
+
throw new Error(`refusing to overwrite existing file: ${candidate}. Choose a new output name.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return real;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,sDAAsD;AACtD,MAAM,UAAU,WAAW;IACzB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IAC1D,MAAM,IAAI,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,uDAAuD,IAAI,IAAI;YAC7D,6DAA6D,CAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,MAAc;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,CAAS,EAAE,IAAY;IACpD,OAAO,IAAI,KAAK,CACd,GAAG,IAAI,KAAK,CAAC,uCAAuC,IAAI,KAAK;QAC3D,uDAAuD;QACvD,wDAAwD,CAC3D,CAAC;AACJ,CAAC;AAED;iFACiF;AACjF,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,IAAY;IAClD,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;+CAG+C;AAC/C,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,IAAY;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/D,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC;QACrD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,wCAAwC,SAAS,6BAA6B,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omitly-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Model Context Protocol server exposing Omitly's local, verifiable PDF redaction to AI agents. Redaction runs on-device — documents are never uploaded.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"pdf",
|
|
10
|
+
"redaction",
|
|
11
|
+
"claude",
|
|
12
|
+
"ai",
|
|
13
|
+
"agent",
|
|
14
|
+
"local",
|
|
15
|
+
"privacy"
|
|
16
|
+
],
|
|
5
17
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
18
|
+
"homepage": "https://omitly.app/mcp",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/ghadmin-innisfallen-master/omitly"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"omitly-mcp": "dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"!dist/**/*.test.*",
|
|
29
|
+
"wasm",
|
|
30
|
+
"skill",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"THIRD-PARTY-NOTICES.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build:wasm": "wasm-pack build ../crates/leakcheck-wasm --target nodejs --out-dir ../../omitly-mcp/wasm --release && rm -f wasm/.gitignore",
|
|
37
|
+
"build": "npm run build:wasm && tsc",
|
|
38
|
+
"start": "node dist/index.js",
|
|
39
|
+
"dev": "tsc --watch",
|
|
40
|
+
"test": "npm run build:wasm && tsc && node --test \"dist/**/*.test.js\"",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
45
|
+
"zod": "^3.23.8"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.0.0",
|
|
49
|
+
"generate-license-file": "4.2.1",
|
|
50
|
+
"typescript": "^5.5.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
}
|
|
8
55
|
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: omitly-redaction
|
|
3
|
+
description: >-
|
|
4
|
+
Redact PDFs and audit redactions on-device with Omitly. Use when the user wants
|
|
5
|
+
to remove sensitive data (SSNs, emails, names, account numbers) from a PDF, check
|
|
6
|
+
whether an already-"redacted" PDF still leaks data underneath its black boxes, or
|
|
7
|
+
locate PII in a document — all without uploading the file anywhere. Triggers:
|
|
8
|
+
"redact this PDF", "is this redaction safe", "did the black boxes actually work",
|
|
9
|
+
"scrub PII from this document", "check this redacted file".
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Omitly redaction
|
|
13
|
+
|
|
14
|
+
Omitly removes sensitive data from PDFs **on the user's machine** and proves it's
|
|
15
|
+
gone. Nothing is uploaded. These tools come from the `omitly-mcp` server; they
|
|
16
|
+
shell out to a local engine, so the file's bytes never leave the device.
|
|
17
|
+
|
|
18
|
+
The core insight to convey to users: **a black box drawn over text is not
|
|
19
|
+
redaction.** The characters stay in the file and are trivially recoverable. Omitly
|
|
20
|
+
removes the underlying bytes and independently verifies each region is empty.
|
|
21
|
+
|
|
22
|
+
## Pick the tool by intent
|
|
23
|
+
|
|
24
|
+
- **"Did my redaction actually work?" / auditing a file someone else redacted** →
|
|
25
|
+
`check_redaction` (free, read-only). Reports any PII still in the text layer.
|
|
26
|
+
This is the fastest way to show value: run it first on a supposedly-safe file.
|
|
27
|
+
|
|
28
|
+
- **"What sensitive data is in here?" (review before acting)** →
|
|
29
|
+
`find_sensitive_regions`. Returns candidates (page + coordinates + masked
|
|
30
|
+
preview). Use when the user wants to confirm before anything is removed.
|
|
31
|
+
|
|
32
|
+
- **"Redact these specific things I name" (names, addresses, account refs)** →
|
|
33
|
+
`locate_text` to resolve their coordinates, then `redact_pdf`.
|
|
34
|
+
|
|
35
|
+
- **"Just scrub the obvious PII"** → `redact_by_entity` (scan + remove + verify in
|
|
36
|
+
one step; optionally limit to `kinds` like `["ssn","card"]`).
|
|
37
|
+
|
|
38
|
+
- **Redact known regions** → `redact_pdf`. **Confirm an output** → `verify_redaction`.
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
|
|
42
|
+
1. **Never echo a raw sensitive value.** The tools return *masked* previews
|
|
43
|
+
(`•••-••-6789`) on purpose. Drive redaction by page + coordinates, not by
|
|
44
|
+
repeating the secret back to the user.
|
|
45
|
+
2. **Detection is pattern-based, not complete.** Emails/SSNs are reliable; names,
|
|
46
|
+
addresses, and text inside scanned images need the user's own judgement or the
|
|
47
|
+
desktop app. Say so — don't imply "0 found" means "safe".
|
|
48
|
+
3. **Redaction is irreversible.** For destructive `redact_*` calls, confirm the
|
|
49
|
+
source/output paths with the user and write to a *new* output file.
|
|
50
|
+
4. When a `check_redaction` finds leaks, explain the fix: removing the data for
|
|
51
|
+
real (not covering it) with a verified, audited result is what the Omitly app
|
|
52
|
+
does — https://omitly.app.
|
|
53
|
+
|
|
54
|
+
## Typical flow
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
user: "I redacted this in Preview — is it actually safe?"
|
|
58
|
+
→ check_redaction(pdfPath) # free audit
|
|
59
|
+
⚠️ finds 4 SSNs still in the text layer
|
|
60
|
+
→ explain: the black boxes only cover them; offer to remove for real
|
|
61
|
+
→ redact_by_entity(pdfPath, outputPath, kinds:["ssn"]) # removes + verifies
|
|
62
|
+
→ verify_redaction(outputPath) # independent confirmation
|
|
63
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Engine/version string for the page footer ("scanned locally by Omitly vX").
|
|
6
|
+
*/
|
|
7
|
+
export function engine_version(): string;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Locate literal strings (names, addresses — whatever the caller's own entity
|
|
11
|
+
* recognition turns up) and return their masked positions, the wasm twin of the
|
|
12
|
+
* engine's `find_text`. Lets the standalone MCP offer `locate_text` without a
|
|
13
|
+
* native binary. `needles_json` is a JSON array of strings; returns the same
|
|
14
|
+
* `ScanResult` shape as `scan` (kind is "text").
|
|
15
|
+
*/
|
|
16
|
+
export function locate(bytes: Uint8Array, needles_json: string): string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Scan PDF bytes for residual sensitive text and return a JSON `ScanResult`.
|
|
20
|
+
*
|
|
21
|
+
* Called from JS as `scan(new Uint8Array(arrayBuffer))`. Always returns JSON;
|
|
22
|
+
* parse errors come back as `{ ok: false, error }` rather than throwing, so the
|
|
23
|
+
* UI has one code path. A non-empty `leaks` list on an *already-redacted* file
|
|
24
|
+
* is the whole point: it means the redaction only painted over the data.
|
|
25
|
+
*/
|
|
26
|
+
export function scan(bytes: Uint8Array): string;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/* @ts-self-types="./leakcheck_wasm.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Engine/version string for the page footer ("scanned locally by Omitly vX").
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
function engine_version() {
|
|
8
|
+
let deferred1_0;
|
|
9
|
+
let deferred1_1;
|
|
10
|
+
try {
|
|
11
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
12
|
+
wasm.engine_version(retptr);
|
|
13
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
14
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
15
|
+
deferred1_0 = r0;
|
|
16
|
+
deferred1_1 = r1;
|
|
17
|
+
return getStringFromWasm0(r0, r1);
|
|
18
|
+
} finally {
|
|
19
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
20
|
+
wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.engine_version = engine_version;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Locate literal strings (names, addresses — whatever the caller's own entity
|
|
27
|
+
* recognition turns up) and return their masked positions, the wasm twin of the
|
|
28
|
+
* engine's `find_text`. Lets the standalone MCP offer `locate_text` without a
|
|
29
|
+
* native binary. `needles_json` is a JSON array of strings; returns the same
|
|
30
|
+
* `ScanResult` shape as `scan` (kind is "text").
|
|
31
|
+
* @param {Uint8Array} bytes
|
|
32
|
+
* @param {string} needles_json
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
function locate(bytes, needles_json) {
|
|
36
|
+
let deferred3_0;
|
|
37
|
+
let deferred3_1;
|
|
38
|
+
try {
|
|
39
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
40
|
+
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export3);
|
|
41
|
+
const len0 = WASM_VECTOR_LEN;
|
|
42
|
+
const ptr1 = passStringToWasm0(needles_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
|
|
43
|
+
const len1 = WASM_VECTOR_LEN;
|
|
44
|
+
wasm.locate(retptr, ptr0, len0, ptr1, len1);
|
|
45
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
46
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
47
|
+
deferred3_0 = r0;
|
|
48
|
+
deferred3_1 = r1;
|
|
49
|
+
return getStringFromWasm0(r0, r1);
|
|
50
|
+
} finally {
|
|
51
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
52
|
+
wasm.__wbindgen_export2(deferred3_0, deferred3_1, 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.locate = locate;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Scan PDF bytes for residual sensitive text and return a JSON `ScanResult`.
|
|
59
|
+
*
|
|
60
|
+
* Called from JS as `scan(new Uint8Array(arrayBuffer))`. Always returns JSON;
|
|
61
|
+
* parse errors come back as `{ ok: false, error }` rather than throwing, so the
|
|
62
|
+
* UI has one code path. A non-empty `leaks` list on an *already-redacted* file
|
|
63
|
+
* is the whole point: it means the redaction only painted over the data.
|
|
64
|
+
* @param {Uint8Array} bytes
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
function scan(bytes) {
|
|
68
|
+
let deferred2_0;
|
|
69
|
+
let deferred2_1;
|
|
70
|
+
try {
|
|
71
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
72
|
+
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export3);
|
|
73
|
+
const len0 = WASM_VECTOR_LEN;
|
|
74
|
+
wasm.scan(retptr, ptr0, len0);
|
|
75
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
76
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
77
|
+
deferred2_0 = r0;
|
|
78
|
+
deferred2_1 = r1;
|
|
79
|
+
return getStringFromWasm0(r0, r1);
|
|
80
|
+
} finally {
|
|
81
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
82
|
+
wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.scan = scan;
|
|
86
|
+
function __wbg_get_imports() {
|
|
87
|
+
const import0 = {
|
|
88
|
+
__proto__: null,
|
|
89
|
+
__wbg_getRandomValues_cc7f052a444bb2ce: function() { return handleError(function (arg0, arg1) {
|
|
90
|
+
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
91
|
+
}, arguments); },
|
|
92
|
+
__wbindgen_object_drop_ref: function(arg0) {
|
|
93
|
+
takeObject(arg0);
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
__proto__: null,
|
|
98
|
+
"./leakcheck_wasm_bg.js": import0,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function addHeapObject(obj) {
|
|
103
|
+
if (heap_next === heap.length) heap.push(heap.length + 1);
|
|
104
|
+
const idx = heap_next;
|
|
105
|
+
heap_next = heap[idx];
|
|
106
|
+
|
|
107
|
+
heap[idx] = obj;
|
|
108
|
+
return idx;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function dropObject(idx) {
|
|
112
|
+
if (idx < 1028) return;
|
|
113
|
+
heap[idx] = heap_next;
|
|
114
|
+
heap_next = idx;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getArrayU8FromWasm0(ptr, len) {
|
|
118
|
+
ptr = ptr >>> 0;
|
|
119
|
+
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let cachedDataViewMemory0 = null;
|
|
123
|
+
function getDataViewMemory0() {
|
|
124
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
125
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
126
|
+
}
|
|
127
|
+
return cachedDataViewMemory0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getStringFromWasm0(ptr, len) {
|
|
131
|
+
return decodeText(ptr >>> 0, len);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let cachedUint8ArrayMemory0 = null;
|
|
135
|
+
function getUint8ArrayMemory0() {
|
|
136
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
137
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
138
|
+
}
|
|
139
|
+
return cachedUint8ArrayMemory0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getObject(idx) { return heap[idx]; }
|
|
143
|
+
|
|
144
|
+
function handleError(f, args) {
|
|
145
|
+
try {
|
|
146
|
+
return f.apply(this, args);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
wasm.__wbindgen_export(addHeapObject(e));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let heap = new Array(1024).fill(undefined);
|
|
153
|
+
heap.push(undefined, null, true, false);
|
|
154
|
+
|
|
155
|
+
let heap_next = heap.length;
|
|
156
|
+
|
|
157
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
158
|
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
159
|
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
160
|
+
WASM_VECTOR_LEN = arg.length;
|
|
161
|
+
return ptr;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
165
|
+
if (realloc === undefined) {
|
|
166
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
167
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
168
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
169
|
+
WASM_VECTOR_LEN = buf.length;
|
|
170
|
+
return ptr;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let len = arg.length;
|
|
174
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
175
|
+
|
|
176
|
+
const mem = getUint8ArrayMemory0();
|
|
177
|
+
|
|
178
|
+
let offset = 0;
|
|
179
|
+
|
|
180
|
+
for (; offset < len; offset++) {
|
|
181
|
+
const code = arg.charCodeAt(offset);
|
|
182
|
+
if (code > 0x7F) break;
|
|
183
|
+
mem[ptr + offset] = code;
|
|
184
|
+
}
|
|
185
|
+
if (offset !== len) {
|
|
186
|
+
if (offset !== 0) {
|
|
187
|
+
arg = arg.slice(offset);
|
|
188
|
+
}
|
|
189
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
190
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
191
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
192
|
+
|
|
193
|
+
offset += ret.written;
|
|
194
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
WASM_VECTOR_LEN = offset;
|
|
198
|
+
return ptr;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function takeObject(idx) {
|
|
202
|
+
const ret = getObject(idx);
|
|
203
|
+
dropObject(idx);
|
|
204
|
+
return ret;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
208
|
+
cachedTextDecoder.decode();
|
|
209
|
+
function decodeText(ptr, len) {
|
|
210
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const cachedTextEncoder = new TextEncoder();
|
|
214
|
+
|
|
215
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
216
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
217
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
218
|
+
view.set(buf);
|
|
219
|
+
return {
|
|
220
|
+
read: arg.length,
|
|
221
|
+
written: buf.length
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let WASM_VECTOR_LEN = 0;
|
|
227
|
+
|
|
228
|
+
const wasmPath = `${__dirname}/leakcheck_wasm_bg.wasm`;
|
|
229
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
230
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
231
|
+
let wasmInstance = new WebAssembly.Instance(wasmModule, __wbg_get_imports());
|
|
232
|
+
let wasm = wasmInstance.exports;
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const engine_version: (a: number) => void;
|
|
5
|
+
export const locate: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
6
|
+
export const scan: (a: number, b: number, c: number) => void;
|
|
7
|
+
export const __wbindgen_export: (a: number) => void;
|
|
8
|
+
export const __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
9
|
+
export const __wbindgen_export2: (a: number, b: number, c: number) => void;
|
|
10
|
+
export const __wbindgen_export3: (a: number, b: number) => number;
|
|
11
|
+
export const __wbindgen_export4: (a: number, b: number, c: number, d: number) => number;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "leakcheck-wasm",
|
|
3
|
+
"description": "In-browser PDF redaction leak checker — wasm-bindgen wrapper over redaction-core's detector. Runs 100% client-side; no upload.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"files": [
|
|
6
|
+
"leakcheck_wasm_bg.wasm",
|
|
7
|
+
"leakcheck_wasm.js",
|
|
8
|
+
"leakcheck_wasm.d.ts"
|
|
9
|
+
],
|
|
10
|
+
"main": "leakcheck_wasm.js",
|
|
11
|
+
"types": "leakcheck_wasm.d.ts"
|
|
12
|
+
}
|