Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,22 @@ jobs:
name: middev-calibration-readiness
path: calibration-readiness/
if-no-files-found: error

wasm-scan:
name: WASM hidden-scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown

- name: Test crate and build wasm32
run: |
cargo test --manifest-path crates/fuckmark-scan/Cargo.toml
cargo build --release --target wasm32-unknown-unknown --manifest-path crates/fuckmark-scan/Cargo.toml
test -f crates/fuckmark-scan/target/wasm32-unknown-unknown/release/fuckmark_scan.wasm

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ venv/
.env.*
.DS_Store
artifacts/
target/
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Language-aware Trojan Source analysis and autofix. `scan_hidden_characters(..., language=)` (and lint, from the file suffix) classifies source as `comment` / `string` / code. `autofix_trojan_source` / `autofixTrojanSource` strip only `bidi_control`.
- Zero-install hidden-Unicode scan page: `docs/scan.html` (packaged as `fuckmark/webui/scan.html`, engine copy `scan.js`). `fuckmark web` serves it at `/scan.html`. After deploy: `mark.q1z.org/scan.html`. Scanning runs in the browser; a local Python `/api/scan` confirm is optional when the CLI server is up.
- Chromium browser extension under `editors/browser`: popup scanner, on-page reveal (badges plus CSS highlights), context-menu scan, per-tab toolbar badge, and optional paste-safe stripping that keeps real emoji ZWJ sequences (both neighbors emoji) and stops page paste handlers from seeing the raw clipboard. Zero remote code; `scan.js` matches the VS Code engine copy. Load unpacked from `chrome://extensions`.
- WASM build of `fuckmark-hidden-scan-v1` (`crates/fuckmark-scan`, committed `fuckmark_scan.wasm`). The scan page and the Chromium popup load it when `fetch` works so classification stays on-device; `scan.js` remains the `file://` fallback. Lone UTF-16 surrogates route through the JS engine (UTF-8 cannot carry them). Empty category arrays stay empty selections. The extension CSP allows `wasm-unsafe-eval` so Chromium can instantiate the module. Page reveal and paste-safe keep the synchronous JS port. Rebuild with `crates/fuckmark-scan/build-wasm.sh`.
- `fuckmark normalize` (`fuckmark-normalize-v1`): NFC, optional identifier lookalike fold (UTS #39-inspired subset, not a full confusable map), then strip of the security category set, plus a JSON receipt (`input_sha256` / `output_sha256` / `steps` / `report_hash`). `--clean` remains the blunt strip with no receipt. HTTP: `POST /api/normalize`. Python: `normalize_text`, `skeleton_fold`. Reference: `docs/normalize.md`.
- VS Code / Cursor: `fuckmark.cleanOnSave` (default off) strips hidden Unicode on save.
- Frozen confirmation files, hashes, mix mechanisms, and the published wheel are unchanged. Package version stays 0.4.1.
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Opens a local page at `http://127.0.0.1:8765/mark.html`. Paste text in the brows
`fuckmark web` also serves a local Python API. Detect and strip POST to `/api/remove-marks` and run the same engine as `fuckmark --detect`. Opening `mark.html` with `file://` or the static website has no Python process, so those paths keep the in-browser fallback.

- Product paste UI source: [`docs/mark.html`](docs/mark.html) (packaged as `fuckmark/webui/mark.html`) — after deploy: [mark.q1z.org/mark.html](https://mark.q1z.org/mark.html)
- Hidden-Unicode scan (no install): [`docs/scan.html`](docs/scan.html) — `file://` works; `fuckmark web` serves `/scan.html`; after deploy: [mark.q1z.org/scan.html](https://mark.q1z.org/scan.html)
- Hidden-Unicode scan (no install): [`docs/scan.html`](docs/scan.html) — `file://` works; `fuckmark web` serves `/scan.html`; after deploy: [mark.q1z.org/scan.html](https://mark.q1z.org/scan.html). The page prefers a local WASM copy of the same classifier (`fuckmark_scan.wasm`) and falls back to `scan.js`.
- Research demo: [`docs/demo.html`](docs/demo.html) — `file://` works; after deploy: [mark.q1z.org/demo.html](https://mark.q1z.org/demo.html)

`mark.html` runs a local closed-set FuckMark scan, strips approved insertions when found, and on a miss shows an English no-watermark card with contact to `Fhelp@q1z.org`. Under `fuckmark web` that scan is the Python detector; the JS copy is the fallback.
Expand Down Expand Up @@ -181,7 +181,7 @@ The [`editors/vscode`](editors/vscode) extension reveals hidden Unicode inline a

## See it in the browser (Chrome / Edge / Brave)

The [`editors/browser`](editors/browser) extension reveals hidden Unicode on the page you are reading. Load it unpacked from `chrome://extensions` (Developer mode). The popup scans pasted text or the current tab, **Reveal** paints `U+XXXX` badges on the page, and **Paste-safe** (off by default) strips hidden characters when you paste into a field while keeping emoji sequences. Nothing is uploaded; the scanner is the same `scan.js` as the editor extension. Full notes: [`editors/browser/README.md`](editors/browser/README.md).
The [`editors/browser`](editors/browser) extension reveals hidden Unicode on the page you are reading. Load it unpacked from `chrome://extensions` (Developer mode). The popup scans pasted text or the current tab, **Reveal** paints `U+XXXX` badges on the page, and **Paste-safe** (off by default) strips hidden characters when you paste into a field while keeping emoji sequences. Nothing is uploaded. The popup prefers `fuckmark_scan.wasm` when it can fetch it; on-page reveal and paste-safe keep `scan.js`. Full notes: [`editors/browser/README.md`](editors/browser/README.md).

## Guard model input (LLM prompt-injection smuggling)

Expand Down Expand Up @@ -255,6 +255,7 @@ Frozen evidence, hashes, and protocols: [`docs/research.md`](docs/research.md).
```text
python -m pip install -e ".[dev]"
python -m pytest
cargo test --manifest-path crates/fuckmark-scan/Cargo.toml
```

## License
Expand Down
7 changes: 7 additions & 0 deletions crates/fuckmark-scan/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions crates/fuckmark-scan/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "fuckmark-scan"
version = "0.4.1"
edition = "2021"
license = "MIT"
publish = false
description = "fuckmark-hidden-scan-v1 classifier for native and wasm32"

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true
18 changes: 18 additions & 0 deletions crates/fuckmark-scan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# fuckmark-scan (Rust / WASM)

Native and `wasm32` build of `fuckmark-hidden-scan-v1`. Same category table as
`editors/vscode/scan.js` and `fuckmark.product.scan`. No network, no extra
crate dependencies.

```text
rustup target add wasm32-unknown-unknown
./crates/fuckmark-scan/build-wasm.sh
```

That writes `fuckmark_scan.wasm` next to the scan page, the packaged web UI,
and the Chromium popup. The page and popup load it when `fetch` works and keep
`scan.js` as the `file://` fallback.

`cargo test` in this directory covers classification, Trojan Source roles, and
clean. Conformance vectors are also replayed from Python via Node on the
committed module.
22 changes: 22 additions & 0 deletions crates/fuckmark-scan/build-wasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh
set -eu
root="$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)"
crate="$root/crates/fuckmark-scan"
cd "$crate"
rustup target add wasm32-unknown-unknown >/dev/null
cargo test --offline --quiet 2>/dev/null || cargo test --quiet
cargo build --release --target wasm32-unknown-unknown --quiet
src="$crate/target/wasm32-unknown-unknown/release/fuckmark_scan.wasm"
test -f "$src"
for dest in \
"$root/editors/wasm/fuckmark_scan.wasm" \
"$root/docs/fuckmark_scan.wasm" \
"$root/fuckmark/webui/fuckmark_scan.wasm" \
"$root/editors/browser/fuckmark_scan.wasm"
do
cp "$src" "$dest"
done
cp "$root/editors/wasm/scan_wasm.js" "$root/docs/scan_wasm.js"
cp "$root/editors/wasm/scan_wasm.js" "$root/fuckmark/webui/scan_wasm.js"
cp "$root/editors/wasm/scan_wasm.js" "$root/editors/browser/scan_wasm.js"
wc -c "$src"
Loading