VerifyKitv0.5.4

Changelog

All notable changes to VerifyKit will be documented in this file.

The format is based on Keep a Changelog.

[0.5.4] -- 2026-04-29

Fixed

Verification engine (core)

  • DSS indirect array references now resolved correctly. The Document Security Store parser previously only handled inline arrays (/OCSPs [77 0 R 78 0 R]); when a PDF stored the array as a separate object (/OCSPs 84 0 R where object 84 is the array), OCSPs/CRLs/Certs were silently read as empty. Added resolve_dss_array which tries inline first and falls back to dereferencing the indirect object. Fixes LTV detection and PAdES level reporting (was B-T, now correctly B-LTA) for PDFs produced by Adobe Acrobat, DocuSign, and other signers that emit DSS with indirect arrays.

  • dss_only_beyond_coverage scan window expanded to the full file. The check that detects whether content beyond a signature's byte-range is only DSS/revocation data (a permitted post-signing update) was limited to the first 100 KB past the coverage end. For large PDFs or late-appended DSS dictionaries that fall beyond that window the check incorrectly treated the content as a modification and returned unknown for integrity. The window is now the full remaining file length.

  • is_last_signature determined by byte-range coverage end, not vector index. When expand_shared_sig_fields clones a CAdES signature value across multiple AcroForm fields, the clones are appended to the end of the signature vector. The previous idx == sig_count - 1 logic picked a clone as the "last" signature, causing a false "document has been modified since it was signed" warning on the actual last signature (the RFC 3161 document timestamp). The flag is now set on whichever signature has the highest offset2 + length2 byte-range end, which is always the document timestamp.


[0.5.3] -- 2026-04-24

Added

Verification engine (core)

  • Configurable algorithm policy — Adobe-parity default for deprecated algorithms with opt-in strict mode.
    • New AlgorithmPolicy type + VerifyKitCoreConfig.algorithmPolicy option. Shape: { sha1: 'valid' | 'warn' }.
    • Default is { sha1: 'valid' } to match Adobe Reader: SHA-1 family signatures pass the algorithm-strength check and surface the algorithm name via the new SignatureCheckResult.algorithmName field, so UIs can render a "Signed with SHA-1" disclosure without marking the overall signature as warning.
    • Set { sha1: 'warn' } to surface SHA-1 signatures as warnings (pre-0.5.3 behavior).
    • Runtime helpers setAlgorithmPolicy(policy) / resetAlgorithmPolicy() exported from @trexolab/verifykit-core and @trexolab/verifykit-react.
    • MD5 / MD2 / MD4 remain hardcoded Invalid and cannot be overridden — they are cryptographically broken, not merely deprecated.
  • SignatureCheckResult.algorithmName — optional human-readable algorithm name (e.g. "SHA-1", "SHA-256 with RSA") populated by the algorithm-strength check regardless of status, enabling integrators to build their own badge UI.
  • CertificateInfo.rawDer (Uint8Array) — raw DER-encoded certificate bytes are now included in the WASM output so UIs can offer per-cert and chain export. The verification pipeline never reads this field; it is serialization-only (#[serde(skip_serializing_if = "Option::is_none")]).
  • buildCertChainPkcs7(certs) — new core helper that assembles a degenerate CMS SignedData (certs-only PKCS#7 / .p7b) from a CertificateInfo[]. Pure Rust ASN.1 encoding, no cryptographic operations, completely decoupled from the verification pipeline.

React / viewer

  • Certificate chain export from the Signature Properties dialog. The Certificates tab (and the TSA tab when TSA certs are embedded) now shows an Export Chain ▾ dropdown with three formats:
    • PEM chain (.pem) — all certs concatenated as -----BEGIN CERTIFICATE----- blocks, ready for Unix / server / Java trust stores.
    • PKCS#7 bundle (.p7b) — Windows / Adobe Reader native import format.
    • All certificates (.zip) — one NN-<CN>.pem + NN-<CN>.cer pair per cert, written by a dependency-free stored-ZIP writer (CRC-32 + local / central / EOCD records). Exports sort from signer to root.
    • Default filename: <signerCN>-chain.{pem,p7b,zip} with filesystem-safe sanitization.
    • Existing per-cert PEM / DER buttons in CertificateViewer.DetailPanel now actually render (they always existed but required rawDer), covering "export signer" and "export any individual certificate" without new UI.
  • exportCertChainAsPem, exportCertChainAsPkcs7, exportCertChainAsZip re-exported from @trexolab/verifykit-react alongside the existing exportCertAsPem / exportCertAsDer.
  • React signature list panel shows an Adobe-style Signed with SHA-1 (legacy algorithm). disclosure in the expanded signature summary when a legacy algorithm is detected.
  • Configurable zoom range. zoomPlugin() now accepts ZoomPluginOptions { minScale?, maxScale?, step? }; defaultLayoutPlugin({ zoom }) and vanilla VerifyKit.create({ zoom }) pipe the same option through. The zoom dropdown filters presets to the configured range so no unreachable level is ever offered. New preset levels: 25%, 600%, 800%, 1000%.

Demo site + SEO

  • /faq page with 12 developer-focused Q&A and full FAQPage JSON-LD schema (FAQ accordion can appear directly in Google SERP).
  • Richer structured data — root layout now emits Organization (with sameAs links to GitHub / npm / Twitter), enriched WebSite (with SearchAction), and SoftwareApplication on every page alongside any page-specific schemas. /docs/quick-start gets a HowTo schema so Google can render a numbered-step carousel.
  • IndexNow protocol wired — /<key>.txt verification file served from apps/demo/public/ + new npm run indexnow:submit script. After a content update the script pings IndexNow so Bing / Yandex / DuckDuckGo / Naver / Seznam re-crawl immediately instead of waiting days.
  • Search engine verification via env varsNEXT_PUBLIC_BING_VERIFICATION, NEXT_PUBLIC_YANDEX_VERIFICATION, NEXT_PUBLIC_GOOGLE_VERIFICATION. Values are emitted as <meta> tags via Next.js Metadata.verification; documented in apps/demo/.env.example.
  • docs/seo-onboarding.md — post-deploy checklist covering Google Search Console sitemap submission, Bing Webmaster import, IndexNow usage, GitHub repo SEO (description / topics / website field), directory submissions, and a content-calendar guideline.
  • Sitemap extended to include /faq.

Documentation

  • docs/security.md — new "Algorithm Policy" section (tier table, Adobe-parity rationale, opt-in code sample).
  • docs/api/core.mdAlgorithmPolicy type, setAlgorithmPolicy / resetAlgorithmPolicy function references, algorithmName field on SignatureCheckResult.
  • docs/api/react.mdZoomPluginOptions documented on zoomPlugin() and DefaultLayoutPluginOptions.
  • docs/customization.md — new "Zoom range" section with React à-la-carte, defaultLayoutPlugin, and vanilla examples.
  • docs/seo-onboarding.md — new (see above).

Changed

Behavior

  • Default overall status for pure-SHA-1 signatures — signatures whose only issue was the SHA-1 algorithm previously produced overallStatus: 'warning'; with the new Adobe-parity default they produce overallStatus: 'valid'. Integrations relying on the old behavior can pass { algorithmPolicy: { sha1: 'warn' } } to createVerifier() or call setAlgorithmPolicy({ sha1: 'warn' }).
  • Default zoom range — min 0.40.25, max 510 (40%–500% → 25%–1000%, matching pdf.js). Restore the old range with zoom: { minScale: 0.4, maxScale: 5 }.

Visual / theme

  • Light-theme contrast tuned across the docs site and the SDK viewer (CSS tokens only, no component changes). Docs-site card/border tokens widened so cards are distinguishable from the background; SDK viewer --fg-muted, --fg-subtle, --border, tab-bar / status-bar / find-bar / floating-menu text tokens darkened to hit WCAG AA 4.5:1 on white. Dark theme untouched.

Monorepo layout & naming

  • Root package renamed verifykitverifykit-monorepo (private, never published; removes ambiguity with the PM2 process name and with the @trexolab/verifykit-* family).
  • Demo moved apps/apps/demo/ to match the conventional monorepo layout and keep apps/ as a parent directory. git mv preserved history. package.json workspaces glob updated to apps/* so future apps drop in without further config changes.
  • PM2 process renamed verifykitverifykit-demo (disambiguates from the package name). npm run pm2:demo is now idempotent — it restarts the existing PM2 entry in place instead of creating a duplicate on every re-run (the root cause of the stopped-entry zombie pileup).
  • scripts/pack-registry.mjs, apps/demo/next.config.ts, and filesystem-coupled demo modules (docs / blog / search-index / logs / session-store / feature-toggles / origins-store) updated to the new apps/demo/ path.

Fixed

Verification engine

  • Legacy adbe.pkcs7.sha1 signatures now verify correctly. Signatures using the PDF 1.3 PKCS#7 format — where encapContentInfo.eContent IS the SHA-1 hash of the byte-range bytes and signedAttrs are absent — were previously reported as INVALID with "document has been modified or corrupted." The Rust engine now recognises this format: the integrity check compares SHA-1(signed_bytes) against eContent, and CMS verification falls back to verifying the signature directly over eContent per RFC 5652 §5.4 when signedAttrs are missing. Restores Adobe Reader parity for multi-signature PDFs that mix a modern CAdES certification signature with a legacy SHA-1 approval signature.

JS / React wrapper

  • rehydrateDates() was destructuring Uint8Array values returned from WASM into plain {0: byte, …} objects because the recursive walker did not special-case typed arrays. Binary fields (e.g. the new CertificateInfo.rawDer) now pass through verbatim. Date rehydration itself is unchanged.
  • TypeScript 5.7+ BlobPart narrowingUint8Array<ArrayBufferLike> (which includes SharedArrayBuffer) is no longer assignable to BlobPart. The two new chain-export helpers (exportCertChainAsPkcs7, exportCertChainAsZip) now cast to BlobPart explicitly; runtime buffers are always plain ArrayBuffer, so behavior is unchanged.
  • Certificate chain row in CertificateViewer mixed shorthand (borderLeft, border: 'none') with longhand (borderLeftStyle/Width/Color) properties on the same <button>, triggering a React dev-mode warning. Replaced with per-side longhand properties; visual output is unchanged.

Demo site

  • /docs/* routes returned 404 in production after the apps/ → apps/demo/ move because nine files resolved paths with process.cwd() + "../", which pointed at the repo root when the app lived at apps/ but pointed at the (removed) apps/ parent after the move. Content readers (docs.ts, blog/[slug]/page.tsx, api/search-index/route.ts) now try cwd, cwd/.., and cwd/../.. so they work from the repo root, from apps/, or from apps/demo/. Filesystem-coupled stores (log-store, session-store, feature-toggles, origins-store, heartbeat, dashboard) now use cwd/../../logs for the fixed repo-root logs/ directory.
  • Build artifacts leaked into git after the apps/ move because .gitignore patterns still pointed at the old apps/public/cdn/ and apps/public/registry/tarballs/ paths. Patterns updated to apps/demo/public/...; previously-tracked artifacts git rm --cached-ed.

Developer experience

  • [build:demo] npm script was unusable — the key literally contained the square brackets ("[build:demo]"), so npm run build:demo never matched. Renamed to build:demo.

Internal

  • scripts/sync-version.mjs now carries a comment explaining why apps/demo/package.json is intentionally excluded from the version-sync list (private, never published, no API contract to the SDK version).
  • package-lock.json regenerated from scratch after the workspaces glob changed to apps/*, dropping the stale "apps" entry.
  • All 9 core Rust unit tests pass (5 existing + 4 new cms_builder tests). End-to-end verification snapshot against signPDF_1Signed.pdf is byte-identical across every commit in this release.

[0.5.2] -- 2026-04-22

Fixed

  • PAdES level detection now correctly reports B-LTA for signatures covered by a later ETSI.RFC3161 document-time-stamp when the DSS carries complete chain revocation data. Previously, a signature whose embedded TSTInfo failed to parse was demoted to B-B and the archive-timestamp promotion step only handled B-LT → B-LTA, so such files were misclassified relative to Adobe Reader DC.
  • Timestamp evidence for PAdES classification now recognises the presence of the signature-time-stamp unsigned attribute (matching Adobe Reader), instead of requiring a fully verified TSTInfo.
  • Archive-timestamp promotion extended to cover B-B / B-T → B-LTA when the covered signature has complete chain revocation data, not just B-LT → B-LTA.

[0.5.0] -- 2026-03-26

Improved

  • Full codebase audit: resolved all TypeScript type errors, unused variables, and dead code across core, react, and plugin-revocation packages
  • Rust/WASM engine: zero clippy warnings — replaced manual iterator patterns with idiomatic contains(), strip_prefix(), ? operator, and const thread-local initializers
  • Removed dead functions (injectIconIntoStream, getBannerSub), unused imports, and stale constants
  • Fixed type safety in plugin-revocation handler and proxy request paths
  • ESLint configuration overhauled: proper ignore patterns for generated files, _-prefix convention for unused params, removed inapplicable react-refresh rules
  • All workspace dependency references aligned to wildcard (*) for consistent local resolution
  • Fresh production builds verified clean across all packages

[0.4.6] -- 2026-03-26

Added

  • PAdES conformance tab in signature properties with progress bar and level timeline
  • PAdES level badges (B-T, B-LT, B-LTA) and TIMESTAMP badge in signature panel
  • Document Timestamp label and TSA name display for ETSI.RFC3161 signatures
  • SDK logo in viewer About modal, documentation header, and favicon
  • Branded name with logo colors (Verify in cyan, Kit in default)
  • About modal redesigned with logo, capability pills, link cards, and TrexoLab product link
  • Five new documentation pages: Security, Testing, Internationalization, Browser Support, Error Reference
  • Documentation version badge in website header (read from root package.json at build time)

Fixed

  • PAdES B-LTA detection: upgrade B-LT signatures when followed by RFC3161 document timestamp
  • PAdES level detection restricted to ETSI signatures only (PKCS#7 signatures no longer incorrectly tagged as PAdES)
  • padesLevel field now optional (null for non-PAdES signatures like adbe.pkcs7.detached)
  • Documentation audit: 15 files corrected (wrong props, broken examples, stale versions, missing types)

Changed

  • Details tab redesigned: verdict-first layout, verification checks promoted, signer card with avatar
  • Removed GitHub references from documentation website
  • All hardcoded version numbers removed from documentation (single source of truth via root package.json)

[0.4.5] -- 2026-03-26

Fixed

  • Display status aligned with Adobe Reader DC default behavior — valid signatures with unchecked revocation now show as "Valid" instead of "Unknown" (matches Adobe's non-strict revocation mode)
  • Missing React key props in plugin overlay, right panel, and page overlay collection functions

Added

  • Changelog page added to documentation site
  • Mermaid diagram rendering support in documentation
  • Architecture diagrams (SDK overview + verification pipeline) using Mermaid
  • "Adobe Reader Aligned" capability added to About modal
  • npm run version:sync script — single source of truth for version across all packages
  • Version and release guide (docs/creating-a-package.md)

Changed

  • About modal redesigned — technology-neutral descriptions, cleaner layout with bordered cards, copyright footer
  • Polyfills no longer need separate import — auto-included via main entry point

[0.4.4] -- 2026-03-25

Added

  • Certificate chain resolution with AKI/SKI matching and PKCS#7 embedded certificate support
  • Acro6 layer icons loaded from SVG source files instead of hardcoded paths

Fixed

  • Signature display aligned with Adobe Reader for expired certificates, certification level, and N4 text
  • Keyboard shortcuts now toggle instead of one-shot activate
  • Multi-field signatures sharing a single PKCS#7 blob are correctly detected
  • Unknown signature status aligned with Adobe Reader DC behavior
  • Signature validation for malformed PDFs aligned with Adobe Reader
  • H/V SVG path commands handled in Acro6 icon converter

Changed

  • Documentation synced with recent SDK changes
  • Homepage redesigned with stone palette, SEO metadata, and grid sections
  • Demo site restyled with dark-first design tokens, Geist fonts, muted palette, and flat styles

[0.4.3] -- 2026-03-17

Fixed

  • ETSI.RFC3161 document timestamp integrity check -- use TSTInfo messageImprint instead of signedAttrs messageDigest for document timestamps (PAdES B-LTA)
  • Document timestamp EKU validation -- accept id-kp-timeStamping (1.3.6.1.5.5.7.3.8) for TSA certificates instead of requiring document-signing EKUs
  • PDF field name extraction from binary stream data -- strict delimiter validation prevents /T matches inside compressed streams from corrupting the field name
  • Signature widget overlay matching for multi-page fields -- handle sibling-replica suffix (_sr{N}) and shared /V reference patterns
  • Appearance layer swap (Acro6) for PDFs with multiple widget annotations sharing a single signature value
  • Revocation check leniency for failed document timestamps -- require valid CMS signature before granting timestamp grace period

Added

  • Scroll-to-signature on panel click -- viewport centers on the signature field with 4-blink highlight animation (matching Adobe Reader behavior)
  • Widget registry in signature plugin for cross-page widget lookup
  • Shared field-name-utils.ts utility for normalized field name matching across the codebase

Changed

  • Overall verification messages use "Document timestamp" language for ETSI.RFC3161 signatures instead of generic "Signature" wording
  • Document timestamp signing time extracted from TSTInfo genTime (the CMS itself is the timestamp)
  • Extracted duplicated field name suffix stripping into shared normalizeFieldName() / isSameFieldFamily() helpers (was duplicated in 3 files with inconsistent order)
  • Removed redundant overall_message.to_string() allocation and trivial extract_tst_gen_time_from_econtent wrapper
  • Marked file-dependent integration tests with #[ignore] for CI compatibility

[0.4.2] -- 2026-03-16

Changed

  • Enable wasm-opt -Oz post-compilation pass -- WASM binary reduced by 15.7% (1297 KB to 1093 KB)
  • Switch Rust build from opt-level = 3 to opt-level = "z" (size-optimized) with per-crate overrides keeping crypto crates (RSA, ECDSA, Ed25519) at full speed
  • Async base64 decode via fetch(data:...) in browser -- avoids 1.3 MB intermediate atob() string, reducing peak init memory
  • Trust store refactor: removed unused all field, ownership transfer instead of cloning, single-pass classification with inline root_dns build -- reduces heap allocations by ~1 MB

[0.4.1] -- 2026-03-16

Fixed

  • Support BER indefinite-length CMS encoding (0x30 0x80) -- PDF signatures using this encoding were rejected by the ASN.1 parser, causing all verification checks to cascade-fail
  • DSS extraction now resolves latest object revision in incremental PDF updates -- fixes LTV/DSS revocation data not being found when the catalog was updated after signing

Changed

  • Bump version to 0.4.1

[0.4.0] -- 2026-03-16

Changed

  • Version bump to 0.4.0

[0.3.3] -- 2026-03-16

Changed

  • Flicker-free appearance swap for PDF page rendering
  • Single-render VerificationFloater for improved performance

Added

  • Automated registry and CDN update via npm run pack:registry command

[0.3.2] -- 2026-03-15

Added

  • Embedded VerificationFloater component in the viewer
  • Smart context menu with signature-aware actions
  • Live demo page
  • CORS headers on revocation API route for cross-origin requests
  • Revocation guide added to documentation navigation

Changed

  • workerUrl is now mandatory -- removed auto-detection and bundled worker
  • Updated all documentation for mandatory workerUrl configuration
  • Updated Viewer props API

Fixed

  • pdfjs-dist getOrInsertComputed compatibility error
  • Polyfill issues resolved

[0.3.1] -- 2026-03-13

Added

  • Base64-embedded WASM binary for universal bundler compatibility -- no external .wasm file needed, works in Vite, webpack, Next.js, Node.js, Deno, and Bun with zero configuration
  • Comprehensive documentation update covering all packages
  • pack-registry script for building registry tarballs

Changed

  • Aligned all packages to v0.3.1
  • Fixed type declaration paths across all packages
  • Removed registry tarballs from git tracking