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 Rwhere object 84 is the array), OCSPs/CRLs/Certs were silently read as empty. Addedresolve_dss_arraywhich tries inline first and falls back to dereferencing the indirect object. Fixes LTV detection and PAdES level reporting (wasB-T, now correctlyB-LTA) for PDFs produced by Adobe Acrobat, DocuSign, and other signers that emit DSS with indirect arrays. -
dss_only_beyond_coveragescan 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 returnedunknownfor integrity. The window is now the full remaining file length. -
is_last_signaturedetermined by byte-range coverage end, not vector index. Whenexpand_shared_sig_fieldsclones a CAdES signature value across multiple AcroForm fields, the clones are appended to the end of the signature vector. The previousidx == sig_count - 1logic 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 highestoffset2 + length2byte-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
AlgorithmPolicytype +VerifyKitCoreConfig.algorithmPolicyoption. 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 newSignatureCheckResult.algorithmNamefield, 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-coreand@trexolab/verifykit-react. - MD5 / MD2 / MD4 remain hardcoded
Invalidand cannot be overridden — they are cryptographically broken, not merely deprecated.
- New
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 aCertificateInfo[]. 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) — oneNN-<CN>.pem+NN-<CN>.cerpair 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.DetailPanelnow actually render (they always existed but requiredrawDer), covering "export signer" and "export any individual certificate" without new UI.
- PEM chain (
exportCertChainAsPem,exportCertChainAsPkcs7,exportCertChainAsZipre-exported from@trexolab/verifykit-reactalongside the existingexportCertAsPem/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 acceptsZoomPluginOptions { minScale?, maxScale?, step? };defaultLayoutPlugin({ zoom })and vanillaVerifyKit.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
/faqpage with 12 developer-focused Q&A and fullFAQPageJSON-LD schema (FAQ accordion can appear directly in Google SERP).- Richer structured data — root layout now emits
Organization(withsameAslinks to GitHub / npm / Twitter), enrichedWebSite(with SearchAction), andSoftwareApplicationon every page alongside any page-specific schemas./docs/quick-startgets aHowToschema so Google can render a numbered-step carousel. - IndexNow protocol wired —
/<key>.txtverification file served fromapps/demo/public/+ newnpm run indexnow:submitscript. 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 vars —
NEXT_PUBLIC_BING_VERIFICATION,NEXT_PUBLIC_YANDEX_VERIFICATION,NEXT_PUBLIC_GOOGLE_VERIFICATION. Values are emitted as<meta>tags via Next.jsMetadata.verification; documented inapps/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.md—AlgorithmPolicytype,setAlgorithmPolicy/resetAlgorithmPolicyfunction references,algorithmNamefield onSignatureCheckResult.docs/api/react.md—ZoomPluginOptionsdocumented onzoomPlugin()andDefaultLayoutPluginOptions.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 produceoverallStatus: 'valid'. Integrations relying on the old behavior can pass{ algorithmPolicy: { sha1: 'warn' } }tocreateVerifier()or callsetAlgorithmPolicy({ sha1: 'warn' }). - Default zoom range — min
0.4→0.25, max5→10(40%–500% → 25%–1000%, matchingpdf.js). Restore the old range withzoom: { 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
verifykit→verifykit-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 keepapps/as a parent directory.git mvpreserved history.package.jsonworkspaces glob updated toapps/*so future apps drop in without further config changes. - PM2 process renamed
verifykit→verifykit-demo(disambiguates from the package name).npm run pm2:demois 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 newapps/demo/path.
Fixed
Verification engine
- Legacy
adbe.pkcs7.sha1signatures now verify correctly. Signatures using the PDF 1.3 PKCS#7 format — whereencapContentInfo.eContentIS the SHA-1 hash of the byte-range bytes andsignedAttrsare absent — were previously reported asINVALIDwith "document has been modified or corrupted." The Rust engine now recognises this format: the integrity check comparesSHA-1(signed_bytes)againsteContent, and CMS verification falls back to verifying the signature directly overeContentper RFC 5652 §5.4 whensignedAttrsare 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 destructuringUint8Arrayvalues returned from WASM into plain{0: byte, …}objects because the recursive walker did not special-case typed arrays. Binary fields (e.g. the newCertificateInfo.rawDer) now pass through verbatim. Date rehydration itself is unchanged.- TypeScript 5.7+
BlobPartnarrowing —Uint8Array<ArrayBufferLike>(which includesSharedArrayBuffer) is no longer assignable toBlobPart. The two new chain-export helpers (exportCertChainAsPkcs7,exportCertChainAsZip) now cast toBlobPartexplicitly; runtime buffers are always plainArrayBuffer, so behavior is unchanged. - Certificate chain row in
CertificateViewermixed 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 theapps/ → apps/demo/move because nine files resolved paths withprocess.cwd() + "../", which pointed at the repo root when the app lived atapps/but pointed at the (removed)apps/parent after the move. Content readers (docs.ts,blog/[slug]/page.tsx,api/search-index/route.ts) now trycwd,cwd/.., andcwd/../..so they work from the repo root, fromapps/, or fromapps/demo/. Filesystem-coupled stores (log-store, session-store, feature-toggles, origins-store, heartbeat, dashboard) now usecwd/../../logsfor the fixed repo-rootlogs/directory.- Build artifacts leaked into git after the
apps/move because.gitignorepatterns still pointed at the oldapps/public/cdn/andapps/public/registry/tarballs/paths. Patterns updated toapps/demo/public/...; previously-tracked artifactsgit rm --cached-ed.
Developer experience
[build:demo]npm script was unusable — the key literally contained the square brackets ("[build:demo]"), sonpm run build:demonever matched. Renamed tobuild:demo.
Internal
scripts/sync-version.mjsnow carries a comment explaining whyapps/demo/package.jsonis intentionally excluded from the version-sync list (private, never published, no API contract to the SDK version).package-lock.jsonregenerated from scratch after the workspaces glob changed toapps/*, dropping the stale"apps"entry.- All 9 core Rust unit tests pass (5 existing + 4 new
cms_buildertests). End-to-end verification snapshot againstsignPDF_1Signed.pdfis 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.RFC3161document-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-stampunsigned 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)
padesLevelfield now optional (nullfor non-PAdES signatures likeadbe.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:syncscript — 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
/Tmatches inside compressed streams from corrupting the field name - Signature widget overlay matching for multi-page fields -- handle sibling-replica suffix (
_sr{N}) and shared/Vreference 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.tsutility 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 trivialextract_tst_gen_time_from_econtentwrapper - Marked file-dependent integration tests with
#[ignore]for CI compatibility
[0.4.2] -- 2026-03-16
Changed
- Enable
wasm-opt -Ozpost-compilation pass -- WASM binary reduced by 15.7% (1297 KB to 1093 KB) - Switch Rust build from
opt-level = 3toopt-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 intermediateatob()string, reducing peak init memory - Trust store refactor: removed unused
allfield, ownership transfer instead of cloning, single-pass classification with inlineroot_dnsbuild -- 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:registrycommand
[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
workerUrlis now mandatory -- removed auto-detection and bundled worker- Updated all documentation for mandatory
workerUrlconfiguration - Updated Viewer props API
Fixed
- pdfjs-dist
getOrInsertComputedcompatibility error - Polyfill issues resolved
[0.3.1] -- 2026-03-13
Added
- Base64-embedded WASM binary for universal bundler compatibility -- no external
.wasmfile needed, works in Vite, webpack, Next.js, Node.js, Deno, and Bun with zero configuration - Comprehensive documentation update covering all packages
pack-registryscript 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