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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Started the v2 cycle with a production Image category and local Image Converter.
- Added Image Resize with pixel and percentage modes, aspect-ratio preservation, optional enlargement, Original/JPEG/PNG/WebP output, and local batch ZIP saving.
- Added Image Compressor with Original/JPEG/PNG/WebP output, truthful format-specific quality behavior, unchanged dimensions, and local batch ZIP saving.
- Added the single-file Image Metadata Inspector & Cleaner for JPEG, PNG, and WebP with honest partial/opaque reporting, authoritative Privacy Clean, ICC preservation, and fail-closed verification before save.
- Pinned the immutable `secure-metadata v0.1.0` browser Release artifact as a same-origin dependency with exact provenance and SHA-256 release-gate coverage.
- Added per-file and aggregate compression metrics that distinguish byte savings from larger generated results.
- Added per-image output dimension/pixel checks and a 200-megapixel aggregate resize-output workload limit.
- Added JPEG, PNG, and WebP input/output, lossy quality controls for JPEG/WebP, deterministic white JPEG transparency, metadata-stripping canvas re-encoding, collision-safe Unicode names, and ZIP batch output.
Expand Down
43 changes: 38 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The v1 baseline is recorded in the [changelog](./CHANGELOG.md) and historical [v
- [Image Converter](./tools/image/converter/) — convert batches of JPEG, PNG, and WebP images locally with predictable names and ZIP output.
- [Image Resize](./tools/image/resize/) — resize image batches by pixels or percentage while preserving aspect ratio by default.
- [Image Compressor](./tools/image/compress/) — quality-compress image batches locally and compare original and result sizes.
- [Image Metadata Inspector & Cleaner](./tools/image/metadata/) — inspect supported metadata and save a fail-closed, verified cleaned copy without pixel re-encoding.
- [Images to PDF](./tools/pdf/images-to-pdf/) — arrange JPEG, PNG, and WebP images and save them as one PDF.
- [Merge PDF](./tools/pdf/merge/) — validate, order, and combine PDF pages without rasterizing them.
- [Split PDF](./tools/pdf/split/) — extract ordered page ranges or create predictable per-page and fixed-interval archives.
Expand Down Expand Up @@ -74,7 +75,10 @@ The hub is a static site built with semantic HTML, CSS, and Vanilla JavaScript E
│ ├── ja.js
│ ├── es.js
│ ├── de.js
│ └── fr.js
│ ├── fr.js
│ ├── image-resize.js
│ ├── image-compressor.js
│ └── image-metadata.js
├── tools/
│ ├── shared/
│ │ ├── file.js
Expand All @@ -92,7 +96,10 @@ The hub is a static site built with semantic HTML, CSS, and Vanilla JavaScript E
│ │ └── metadata/
│ ├── image/
│ │ ├── index.html
│ │ └── converter/
│ │ ├── converter/
│ │ ├── resize/
│ │ ├── compress/
│ │ └── metadata/
│ ├── privacy/
│ ├── scan/
│ ├── media/
Expand All @@ -102,12 +109,14 @@ The hub is a static site built with semantic HTML, CSS, and Vanilla JavaScript E
│ ├── jspdf/
│ ├── jszip/
│ ├── pdf-lib/
│ └── pdfjs/
│ ├── pdfjs/
│ └── secure-metadata/
└── tests/
├── ci-foundation.test.mjs
├── home-structure.test.mjs
├── image-to-pdf.test.mjs
├── image-converter.test.mjs
├── image-metadata.test.mjs
├── pdf-merge-and-categories.test.mjs
├── pdf-split.test.mjs
├── pdf-metadata.test.mjs
Expand Down Expand Up @@ -168,6 +177,20 @@ Image Compressor is available at `/tools/image/compress/` on the v2 integration
- Uses collision-safe Unicode `_compressed` names and saves multiple outputs as `compressed_images.zip` through the same-origin JSZip dependency.
- Reuses the established input, queue, dimension, 50-megapixel per-image, and 200-megapixel aggregate decoded-work limits. Queues remain available after recoverable failures or save cancellation.
- Performs no target-size search, resizing, cropping, metadata editing, upload, analytics, telemetry, remote codec, or runtime network request.
## Image Metadata Inspector & Cleaner

Image Metadata Inspector & Cleaner is available at `/tools/image/metadata/` on the v2 integration branch.

- Accepts exactly one signature-validated JPEG, PNG, or WebP file and enforces the application’s 50 MiB limit before full inspection.
- Uses the manually pinned, same-origin `secure-metadata v0.1.0` browser artifact. No npm package, CDN, runtime GitHub request, or automatic version check is used.
- Separates decoded values from opaque detected containers and presents `metadata-partial` as successful but non-exhaustive. “No supported metadata detected” is not a claim that the file contains no metadata.
- Privacy Clean calls the library’s authoritative default policy: supported EXIF, XMP, IPTC, comments, PNG text metadata, and timestamps are removed while ICC color profiles are preserved.
- Keeps source bytes unchanged and never decodes pixels, creates Canvas, resizes, converts, changes quality, or re-encodes the image.
- Calls `verifyMetadata` on cleaned bytes and requires a valid result with every policy check passing before saving. Invalid, incomplete, truncated, or mismatched results fail closed with no output write.
- Derives MIME and the normalized `_clean` filename from the detected image format, not the supplied MIME type or extension.

Detailed wording boundaries and provenance are recorded in [Image Metadata privacy and verification](./docs/image-metadata-privacy.md).


## Images to PDF

Expand Down Expand Up @@ -293,6 +316,17 @@ All processing libraries are pinned and served as same-origin static files. Prod
- Main module and worker: same-origin files under `assets/vendor/pdfjs/`
- Details and hashes: [assets/vendor/pdfjs/README.md](./assets/vendor/pdfjs/README.md)

### secure-metadata

- Version/tag: `v0.1.0`
- Release commit: `352258ec413a838dfe8b9146370505f125b5ae10`
- Purpose: local JPEG, PNG, and WebP metadata inspection, Privacy Clean, and fail-closed verification
- Browser artifact SHA-256: `8d0b8a1addf904760aa1f52378fb05eed6540520cb05fe2320d77011cba69c28`
- License: MIT
- Runtime dependencies: 0
- Integration: manually pinned same-origin GitHub Release artifact; not an npm runtime dependency
- Details and provenance: [assets/vendor/secure-metadata/README.md](./assets/vendor/secure-metadata/README.md)

Each dependency keeps its license and package metadata beside the vendored browser build.

## Local development
Expand All @@ -311,7 +345,7 @@ Run the complete local and CI validation entry point with:
node tests/run-all.mjs
```

It checks JavaScript syntax and runs Image Converter, Images to PDF, PDF Merge, PDF Split, PDF Organizer, PDF to Images, PDF Metadata, category-first homepage, system typography, CJK wrapping, long-copy layout, six-language catalog parity and placeholders, locale detection and persistence, static resource, privacy/network, security-hardening, dependency-integrity, save-path, ZIP, and CI workflow regression coverage. Test fixtures are generated deterministically; CI never processes real user files.
It checks JavaScript syntax and runs Image Converter, Image Resize, Image Compressor, Image Metadata, Images to PDF, PDF Merge, PDF Split, PDF Organizer, PDF to Images, PDF Metadata, category-first homepage, system typography, CJK wrapping, long-copy layout, six-language catalog parity and placeholders, locale detection and persistence, static resource, privacy/network, security-hardening, dependency-integrity, save-path, ZIP, and CI workflow regression coverage. Test fixtures are generated deterministically; CI never processes real user files.

## Production security controls

Expand Down Expand Up @@ -371,7 +405,6 @@ The historical prototype is absent from the deployed tree. External URLs in docu
## Deferred work

- Broader PDF modification, compression, and encryption workflows
- Image resizing, compression, and dedicated metadata inspection/cleaning
- Broader XMP and structural PDF metadata sanitization
- Scan/OCR and media tools
- Offline/PWA support
Expand Down
21 changes: 21 additions & 0 deletions assets/vendor/secure-metadata/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Secure Tools Project contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
19 changes: 19 additions & 0 deletions assets/vendor/secure-metadata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# secure-metadata

Manually pinned browser artifact for local image metadata inspection, cleaning, and verification.

- Library: `secure-metadata`
- Version: `0.1.0`
- Repository: `SecureToolsProject/Secure_Metadata`
- Release tag: `v0.1.0`
- Release commit: `352258ec413a838dfe8b9146370505f125b5ae10`
- Artifact: `secure-metadata-0.1.0.browser.js`
- SHA-256: `8d0b8a1addf904760aa1f52378fb05eed6540520cb05fe2320d77011cba69c28`
- License: MIT; see `LICENSE`
- Runtime dependencies: 0
- Integration: manually pinned, same-origin
- Upgrade policy: explicit reviewed replacement only

The browser artifact was downloaded from the GitHub `v0.1.0` Release and checked locally against both the published `SHA256SUMS` manifest and the approved hash above. Its bytes are unchanged: it was not rebuilt, minified, reformatted, concatenated, or stripped. `LICENSE` and `package.json` were copied from the immutable `v0.1.0` tag.

Secure Tools imports this file only through `tools/image/metadata/metadata.js`. Production pages do not load secure-metadata from npm, a CDN, GitHub, or another runtime origin. Updates require a new explicit provenance and hash review.
74 changes: 74 additions & 0 deletions assets/vendor/secure-metadata/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "secure-metadata",
"version": "0.1.0",
"description": "Deterministic, security-conscious metadata tooling for binary image formats.",
"license": "MIT",
"type": "module",
"sideEffects": false,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./browser": {
"types": "./dist/index.d.ts",
"import": "./dist/browser/secure-metadata.js"
}
},
"files": [
"dist",
"README.md",
"LICENSE",
"CHANGELOG.md"
],
"scripts": {
"build": "tsup && tsup --config tsup.browser.config.ts",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint .",
"test": "vitest run",
"test:watch": "vitest",
"fuzz:smoke": "npm run build --silent && node scripts/fuzz.mjs --seed 20260825 --runs 250 --max-bytes 512",
"fuzz": "npm run build --silent && node scripts/fuzz.mjs",
"typecheck": "tsc --noEmit",
"browser:smoke": "node scripts/browser-smoke.mjs",
"package:audit": "node scripts/release/audit-package.mjs",
"license:audit": "node scripts/release/audit-licenses.mjs",
"version:check": "node scripts/release/check-version.mjs",
"release:build": "node scripts/release/build-artifacts.mjs",
"release:repro": "node scripts/release/check-reproducibility.mjs",
"release:verify": "node scripts/release/verify-hashes.mjs",
"release:check": "node scripts/release/check-rc.mjs"
},
"engines": {
"node": ">=20"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "^24.13.3",
"eslint": "^10.9.0",
"fast-check": "^4.9.0",
"playwright": "^1.62.1",
"prettier": "^3.9.6",
"tsup": "^8.5.1",
"typescript": "5.9.3",
"typescript-eslint": "^8.67.0",
"vitest": "^4.1.11"
},
"overrides": {
"esbuild": "0.28.2"
},
"repository": {
"type": "git",
"url": "git+https://github.com/SecureToolsProject/Secure_Metadata.git"
},
"homepage": "https://github.com/SecureToolsProject/Secure_Metadata#readme",
"bugs": {
"url": "https://github.com/SecureToolsProject/Secure_Metadata/issues"
},
"publishConfig": {
"access": "public"
}
}
Loading
Loading