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
17 changes: 3 additions & 14 deletions .github/workflows/deploy-cloudflare-bridge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,9 @@ jobs:
run: |
set -euo pipefail

npm run build
mkdir -p "$BRIDGE_DIRECTORY"
cp -R \
404.html \
index.html \
about \
assets \
css \
js \
privacy \
robots.txt \
sitemap.xml \
tools \
"$BRIDGE_DIRECTORY/"
cp -R dist/. "$BRIDGE_DIRECTORY/"

printf '%s\n' \
'https://secure-tools-web-bridge.pages.dev/*' \
Expand All @@ -87,10 +77,9 @@ jobs:
> "$BRIDGE_DIRECTORY/_headers"

[[ ! -e "$BRIDGE_DIRECTORY/CNAME" ]]
[[ ! -e "$BRIDGE_DIRECTORY/_redirects" ]]
[[ ! -e "$BRIDGE_DIRECTORY/_worker.js" ]]
[[ ! -d "$BRIDGE_DIRECTORY/functions" ]]
[[ "$(find "$BRIDGE_DIRECTORY" -name index.html -type f | wc -l)" -eq 20 ]]
node scripts/validate-build.mjs "$BRIDGE_DIRECTORY"

- name: Validate Cloudflare Pages project isolation
shell: bash
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules/
dist/
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ See the [privacy model](./docs/privacy-model.md) for exact guarantees and bounda

### PDF

- [Images to PDF](./tools/pdf/images-to-pdf/) — arrange JPEG, PNG, and WebP images and save one PDF.
- [PDF Merge](./tools/pdf/merge/) — combine validated PDFs without rasterizing pages.
- [PDF Split](./tools/pdf/split/) — extract ranges or produce per-page and fixed-interval archives.
- [PDF Organizer](./tools/pdf/organize/) — preview, reorder, rotate, remove, and export pages.
- [PDF to Images](./tools/pdf/to-images/) — render pages to PNG, JPEG, or WebP.
- [PDF Metadata Inspector & Cleaner](./tools/pdf/metadata/) — inspect and remove supported document-info fields.
- [Images to PDF](https://tools.securetools.app/pdf/images-to-pdf/) — arrange JPEG, PNG, and WebP images and save one PDF.
- [PDF Merge](https://tools.securetools.app/pdf/merge/) — combine validated PDFs without rasterizing pages.
- [PDF Split](https://tools.securetools.app/pdf/split/) — extract ranges or produce per-page and fixed-interval archives.
- [PDF Organizer](https://tools.securetools.app/pdf/organize/) — preview, reorder, rotate, remove, and export pages.
- [PDF to Images](https://tools.securetools.app/pdf/to-images/) — render pages to PNG, JPEG, or WebP.
- [PDF Metadata Inspector & Cleaner](https://tools.securetools.app/pdf/metadata/) — inspect and remove supported document-info fields.

### Image

- [Image Converter](./tools/image/converter/) — convert JPEG, PNG, and WebP batches.
- [Image Resize](./tools/image/resize/) — resize batches by pixels or percentage.
- [Image Compressor](./tools/image/compress/) — quality-compress images and compare byte results.
- [Image Metadata Inspector & Cleaner](./tools/image/metadata/) — inspect supported metadata and save a verified cleaned copy without pixel re-encoding.
- [Image Converter](https://tools.securetools.app/image/converter/) — convert JPEG, PNG, and WebP batches.
- [Image Resize](https://tools.securetools.app/image/resize/) — resize batches by pixels or percentage.
- [Image Compressor](https://tools.securetools.app/image/compress/) — quality-compress images and compare byte results.
- [Image Metadata Inspector & Cleaner](https://tools.securetools.app/image/metadata/) — inspect supported metadata and save a verified cleaned copy without pixel re-encoding.

### Privacy

The [Privacy hub](./tools/privacy/) links to the specialized Image and PDF metadata tools. It is a cross-category navigation surface, not a generic sanitizer. Scan/OCR and Media remain planned.
The [Privacy hub](https://tools.securetools.app/privacy/) links to the specialized Image and PDF metadata tools. It is a cross-category navigation surface, not a generic sanitizer. Scan/OCR and Media remain planned.

Detailed formats, limits, and behavior are listed in [tool status](./docs/tool-status.md).

Expand All @@ -45,10 +45,11 @@ Secure Tools includes English, Korean, Japanese, Spanish, German, and French int

## Local development

Serve the repository over HTTP so ES Modules load correctly:
Build the deployable tree, then serve `dist/` over HTTP so ES Modules load correctly:

```bash
python -m http.server 8000
npm run build
python -m http.server 8000 --directory dist
```

Open [http://localhost:8000](http://localhost:8000). Do not use a `file://` URL.
Expand All @@ -62,7 +63,7 @@ npm test
node tests/ocr-smoke.test.mjs
```

The Image category includes a public, single-image [Image → Text OCR](./tools/image/to-text/) workflow for PNG, JPEG, and WebP input. English, Korean, and combined English + Korean recognition run through the same-origin OCR runtime documented in [Local OCR foundation](./docs/ocr-foundation.md).
The Image category includes a public, single-image [Image → Text OCR](https://tools.securetools.app/image/to-text/) workflow for PNG, JPEG, and WebP input. English, Korean, and combined English + Korean recognition run through the same-origin OCR runtime documented in [Local OCR foundation](./docs/ocr-foundation.md).

## Documentation

Expand Down
12 changes: 7 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Application model

Secure Tools is a static GitHub Pages application built with semantic HTML, CSS, and Vanilla JavaScript ES Modules. It has no framework, backend, database, authentication service, or runtime API. Production deploys committed static files directly. A pinned npm preparation step reproduces and verifies the vendored OCR runtime; it does not create a server-side production dependency.
Secure Tools is a static application built with semantic HTML, CSS, and Vanilla JavaScript ES Modules. It has no framework, Vite configuration, backend, database, authentication service, or runtime API. The build stages deployable files in `dist/`; a pinned npm preparation step reproduces and verifies the vendored OCR runtime without creating a server-side production dependency.

Production routes load application code and pinned libraries from the same origin. File-processing workflows run through browser APIs and in-memory data. The [privacy model](./privacy-model.md) defines the limits of that statement.

Expand All @@ -15,7 +15,7 @@ The homepage points to stable category hubs instead of maintaining a flat list o
- Privacy: a cross-category hub for the two metadata tools;
- Scan/OCR and Media: planned, non-interactive surfaces.

Each production tool owns a route under `tools/<category>/<tool>/`. The legacy `/tools/image-to-pdf/` route is a static migration page to `/tools/pdf/images-to-pdf/` with a visible fallback link.
Each production tool has a canonical route at `/<category>/<tool>/`. The `tools/` directory remains the source-code organization, while `scripts/site-routes.mjs` maps its pages into the root-level public namespace. Every previously public `/tools/*` path has a one-hop 308 redirect to its canonical destination. The Privacy policy and metadata-tool hub share `/privacy/` because stripping the old prefix would otherwise collide with the existing policy route.

```text
.
Expand All @@ -27,9 +27,11 @@ Each production tool owns a route under `tools/<category>/<tool>/`. The legacy `
│ ├── shared/ input, validation, output, save, PDF, and UI foundations
│ ├── pdf/ PDF hub and production tools
│ ├── image/ Image hub and production tools
│ ├── privacy/ metadata-tool navigation hub
│ ├── privacy/ source template retained for route-history checks
│ ├── scan/, media/ planned category pages
│ └── image-to-pdf/ legacy static redirect
│ └── image-to-pdf/ retired client-side migration source
├── scripts/site-routes.mjs canonical pages and legacy redirect manifest
├── dist/ generated deployment artifact (ignored)
├── assets/vendor/ pinned same-origin runtime libraries
├── docs/ technical, privacy, and audit records
└── tests/ static and functional validation
Expand Down Expand Up @@ -57,7 +59,7 @@ Image conversion, resizing, and compression use browser decode, Canvas, and enco

## Development and delivery

Serving the committed production tree requires only an HTTP server. Reproducing OCR assets and running the full CI checks requires Node.js 24 and the exact lockfile. `npm run build` verifies prepared OCR assets, `npm test` runs the static and unit suite, and `node tests/ocr-smoke.test.mjs` performs real English, Korean, and combined recognition.
Serving the generated `dist/` tree requires only an HTTP server. Reproducing OCR assets and running the full CI checks requires Node.js 24 and the exact lockfile. `npm run build` verifies prepared OCR assets and stages the site, `npm test` runs the static and unit suite, and `node tests/ocr-smoke.test.mjs` performs real English, Korean, and combined recognition.

`.github/workflows/ci.yml` validates pull requests and pushes to `main` using Node.js 24. It installs the lockfile only to reproduce and verify OCR assets, then checks commit-range whitespace, JavaScript syntax, unit coverage, and real local OCR without adding deployment behavior.

Expand Down
2 changes: 1 addition & 1 deletion docs/image-metadata-privacy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Image Metadata privacy and verification

The Image Metadata Inspector & Cleaner at `/tools/image/metadata/` processes one signature-validated JPEG, PNG, or WebP file in browser memory. The application enforces its existing 50 MiB per-image limit before reading the full file. It does not upload the image, decode pixels, use Canvas, resize, convert, or re-encode it.
The Image Metadata Inspector & Cleaner at `/image/metadata/` processes one signature-validated JPEG, PNG, or WebP file in browser memory. The application enforces its existing 50 MiB per-image limit before reading the full file. It does not upload the image, decode pixels, use Canvas, resize, convert, or re-encode it.

Inspection reports only structures supported by `secure-metadata v0.1.1`. Decoded values and opaque detected containers are presented differently. A `metadata-partial` result is a successful but non-exhaustive inspection; it is not evidence that every possible metadata structure was decoded. “No supported metadata detected” does not mean that the image contains no metadata or hidden information.

Expand Down
6 changes: 4 additions & 2 deletions docs/seo.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The root `CNAME` remains `securetools.app` in H3.4A because this preparation tas

- `/robots.txt` allows public crawling and points to `https://tools.securetools.app/sitemap.xml`.
- `/sitemap.xml` lists exactly the 18 canonical Web Utilities pages intended for indexing.
- The 404 page and legacy `/tools/image-to-pdf/` alias are intentionally `noindex` and absent from the sitemap.
- Redirect-only `/tools/*` URLs and the 404 page are absent from the sitemap.
- No Hub, old apex, GitHub Pages, or `pages.dev` URL belongs in the Web Utilities sitemap.
- Static assets, tests, documentation files, and generated user downloads are not sitemap entries.

Expand Down Expand Up @@ -43,7 +43,7 @@ https://:version.secure-tools-web-bridge.pages.dev/*
X-Robots-Tag: noindex, nofollow
```

This leaves `tools.securetools.app` without the bridge header while retaining duplicate-host protection on stable, branch, and immutable `pages.dev` URLs. It requires no Worker, Pages Function, redirect, or zone-level Transform Rule. The legacy `/tools/image-to-pdf/` page keeps its independent HTML `noindex` directive on every hostname.
This leaves `tools.securetools.app` without the bridge header while retaining duplicate-host protection on stable, branch, and immutable `pages.dev` URLs. It requires no Worker, Pages Function, or zone-level Transform Rule. Cloudflare Pages reads the generated `_redirects` file and permanently redirects each legacy `/tools/*` path to its root-level canonical route with status 308.

## Language and structured data

Expand All @@ -70,6 +70,8 @@ Prolonged partial activation is unsafe because crawlers could see conflicting ca

## Maintenance

Canonical tool URLs use `https://tools.securetools.app/<category>/<tool>/`. Legacy `https://tools.securetools.app/tools/<category>/<tool>/` URLs remain compatibility entry points through permanent redirects and must never appear in canonical metadata or the sitemap.

When an indexable route is added, renamed, redirected, or retired:

1. update its title, description, canonical, and Open Graph metadata;
Expand Down
24 changes: 12 additions & 12 deletions docs/tool-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

| Category | Tool or surface | Status | Formats / scope |
| --- | --- | --- | --- |
| PDF | [Images to PDF](../tools/pdf/images-to-pdf/) | Production | JPEG, PNG, WebP → PDF |
| PDF | [PDF Merge](../tools/pdf/merge/) | Production | Ordered PDF page copying |
| PDF | [PDF Split](../tools/pdf/split/) | Production | Ranges, every page, fixed intervals |
| PDF | [PDF Organizer](../tools/pdf/organize/) | Production | Preview, reorder, rotate, remove, export |
| PDF | [PDF to Images](../tools/pdf/to-images/) | Production | PDF pages → PNG, JPEG, WebP |
| PDF | [PDF Metadata Inspector & Cleaner](../tools/pdf/metadata/) | Production | Eight supported document-info fields |
| Image | [Image Converter](../tools/image/converter/) | Production | JPEG, PNG, WebP conversion |
| Image | [Image Resize](../tools/image/resize/) | Production | Pixel or percentage batch resize |
| Image | [Image Compressor](../tools/image/compress/) | Production | JPEG/WebP quality and PNG re-encoding |
| Image | [Image Metadata Inspector & Cleaner](../tools/image/metadata/) | Production | Supported JPEG, PNG, WebP metadata |
| Image | [Image → Text OCR](../tools/image/to-text/) | Production | One PNG, JPEG, or WebP → editable English/Korean text |
| Privacy | [Privacy hub](../tools/privacy/) | Production hub | Navigation to Image and PDF metadata tools |
| PDF | [Images to PDF](https://tools.securetools.app/pdf/images-to-pdf/) | Production | JPEG, PNG, WebP → PDF |
| PDF | [PDF Merge](https://tools.securetools.app/pdf/merge/) | Production | Ordered PDF page copying |
| PDF | [PDF Split](https://tools.securetools.app/pdf/split/) | Production | Ranges, every page, fixed intervals |
| PDF | [PDF Organizer](https://tools.securetools.app/pdf/organize/) | Production | Preview, reorder, rotate, remove, export |
| PDF | [PDF to Images](https://tools.securetools.app/pdf/to-images/) | Production | PDF pages → PNG, JPEG, WebP |
| PDF | [PDF Metadata Inspector & Cleaner](https://tools.securetools.app/pdf/metadata/) | Production | Eight supported document-info fields |
| Image | [Image Converter](https://tools.securetools.app/image/converter/) | Production | JPEG, PNG, WebP conversion |
| Image | [Image Resize](https://tools.securetools.app/image/resize/) | Production | Pixel or percentage batch resize |
| Image | [Image Compressor](https://tools.securetools.app/image/compress/) | Production | JPEG/WebP quality and PNG re-encoding |
| Image | [Image Metadata Inspector & Cleaner](https://tools.securetools.app/image/metadata/) | Production | Supported JPEG, PNG, WebP metadata |
| Image | [Image → Text OCR](https://tools.securetools.app/image/to-text/) | Production | One PNG, JPEG, or WebP → editable English/Korean text |
| Privacy | [Privacy hub](https://tools.securetools.app/privacy/) | Production hub | Navigation to Image and PDF metadata tools |
| Scan/OCR | Category surface | Planned | No production processing tool |
| Media | Category surface | Planned | No production processing tool |

Expand Down
10 changes: 5 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ <h2 data-i18n="tools.title">Start with what you need to work on.</h2>
<p data-i18n="tools.description">Browse focused categories, then choose a tool. Availability is always shown clearly.</p>
</div>
<div class="category-directory">
<a class="category-card surface" href="./tools/pdf/"><span class="category-card__index">01</span><h3 data-i18n="tools.categories.pdf">PDF</h3><p data-i18n="tools.categoryDescriptions.pdf">Create, combine, and organize documents.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./tools/image/"><span class="category-card__index">02</span><h3 data-i18n="tools.categories.image">Image</h3><p data-i18n="tools.categoryDescriptions.image">Convert and prepare everyday images.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./tools/privacy/"><span class="category-card__index">03</span><h3 data-i18n="tools.categories.privacy">Privacy</h3><p data-i18n="tools.categoryDescriptions.privacy">Inspect and clean supported image or PDF metadata.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./tools/scan/"><span class="category-card__index">04</span><h3 data-i18n="tools.categories.scan">Scan & OCR</h3><p data-i18n="tools.categoryDescriptions.scan">Turn scans into useful documents.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./tools/media/"><span class="category-card__index">05</span><h3 data-i18n="tools.categories.media">Media</h3><p data-i18n="tools.categoryDescriptions.media">Work with audio and video locally.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./pdf/"><span class="category-card__index">01</span><h3 data-i18n="tools.categories.pdf">PDF</h3><p data-i18n="tools.categoryDescriptions.pdf">Create, combine, and organize documents.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./image/"><span class="category-card__index">02</span><h3 data-i18n="tools.categories.image">Image</h3><p data-i18n="tools.categoryDescriptions.image">Convert and prepare everyday images.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./privacy/"><span class="category-card__index">03</span><h3 data-i18n="tools.categories.privacy">Privacy</h3><p data-i18n="tools.categoryDescriptions.privacy">Inspect and clean supported image or PDF metadata.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./scan/"><span class="category-card__index">04</span><h3 data-i18n="tools.categories.scan">Scan & OCR</h3><p data-i18n="tools.categoryDescriptions.scan">Turn scans into useful documents.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
<a class="category-card surface" href="./media/"><span class="category-card__index">05</span><h3 data-i18n="tools.categories.media">Media</h3><p data-i18n="tools.categoryDescriptions.media">Work with audio and video locally.</p><span class="text-link" data-i18n="tools.browseCategory">Browse category →</span></a>
</div>
</div>
</section>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"build": "node scripts/prepare-ocr-assets.mjs --check",
"build": "node scripts/prepare-ocr-assets.mjs --check && node scripts/build-site.mjs",
"prepare:ocr": "node scripts/prepare-ocr-assets.mjs",
"smoke:ocr:browser": "node tests/serve-ocr-smoke.mjs",
"test:commit-messages": "node tests/commit-message.test.mjs",
Expand Down
Loading
Loading