JSignPdf is a Java application for adding digital signatures to PDF documents. It provides both a GUI (JavaFX default, Swing fallback via -Djsignpdf.swing=true) and a CLI interface.
- Java: 21+
- Build: Apache Maven multi-module
- Repository: https://github.com/intoolswetrust/jsignpdf
mvn clean install # Build everything (with tests)
mvn clean install -DskipTests # Build without tests
mvn test -Dtest=BasicSigningTest # Run a single test classjsignpdf-root/
├── jsignpdf-bootstrap/ # Java-8 launcher (Bootstrap.java): JRE-version check + JFX
│ classifier picker + reflective Signer.main. Used by the
│ cross-platform ZIPs (bin/jsignpdf.sh|.cmd → Bootstrap → Signer).
├── jsignpdf/ # Main application (signing logic + GUI + CLI)
├── installcert/ # Certificate installer utility
├── distribution/ # Per-platform packaging — assembles full + minimal ZIPs and
│ drives jpackage for MSI / DEB / RPM / DMG (windows/, linux/,
│ macos/ subfolders) plus the Flatpak manifest.
└── website/ # Hugo documentation site (not a Maven module)
└── docs/JSignPdf.adoc # ★ authoritative user guide (see below)
Keep these in sync with the code; user-facing features are not "done" until they land here too.
| File | Role | When to update |
|---|---|---|
website/docs/JSignPdf.adoc |
Authoritative user guide. Single source of truth consumed by both the Hugo site (website/content/docs/guide/index.adoc is regenerated from it by website/prepare.sh) and the Maven PDF build in distribution/. |
Any new or changed user-visible feature: new CLI flags, new GUI panels, changed defaults, new keystore types, new exit codes, etc. Update the synopsis block, the relevant option table, and add a dedicated subsection if the feature has non-obvious usage. |
distribution/doc/release-notes/<version>.md |
Release notes bundled with the artifact and used as the GitHub Release body. | Every release-worthy change. |
README.md |
Top-level project landing page. Concise feature overview + pointers to the guide. | Only for high-signal changes (new feature categories, platform support, install paths). |
jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages.properties |
Canonical English resource bundle (all others are Weblate-synced). CLI --help text comes from here. |
Any new CLI option or GUI string. Do not hand-edit non-English messages_*.properties files. |
design-doc/<version>-<topic>.md |
Design notes for larger changes. | Before implementing a non-trivial feature. |
When a PR touches a user-visible feature without updating JSignPdf.adoc, flag it as incomplete.
All source is under jsignpdf/src/main/java/net/sf/jsignpdf/:
net.sf.jsignpdf
├── Signer.java # Entry point - launches CLI or GUI
├── SignerLogic.java # Core signing engine (no UI dependencies)
├── BasicSignerOptions.java # Central model for all signing configuration
├── SignPdfForm.java # Swing GUI (legacy, .form files are IDE-generated)
├── fx/ # JavaFX GUI (default)
│ ├── JSignPdfApp.java # Application entry point
│ ├── FxLauncher.java # Static launcher called from Signer.main()
│ ├── view/ # FXML files + controllers (MainWindow, settings panels)
│ ├── viewmodel/ # DocumentViewModel, SigningOptionsViewModel, SignaturePlacementViewModel
│ ├── service/ # PdfRenderService, SigningService, KeyStoreService
│ ├── control/ # PdfPageView, SignatureOverlay
│ └── util/ # FxResourceProvider, SwingFxImageConverter, RecentFilesManager
├── crl/ # Certificate Revocation List handling
├── extcsp/ # External crypto providers (CloudFoxy)
├── preview/ # PDF page rendering (Pdf2Image)
├── ssl/ # SSL/TLS initialization
├── types/ # Enums and value types
└── utils/ # KeyStoreUtils, ResourceProvider, PropertyProvider, etc.
CLI (SignerOptionsFromCmdLine) ──┐
├──> BasicSignerOptions ──> SignerLogic.signFile()
GUI (JavaFX / Swing) ──┘ (model) (signing engine)
BasicSignerOptionsis the central model. Both CLI and GUI populate it, then pass it toSignerLogic.SignerLogicis the signing engine. It has no UI dependencies.- JavaFX GUI uses MVVM: ViewModels with JavaFX properties, FXML views with
%keyi18n, background services wrappingSignerLogicandPdf2Image.
- Resource bundles:
net/sf/jsignpdf/translations/messages*.properties - CLI keys:
console.*,hlp.* - Swing keys:
gui.* - JavaFX keys:
jfx.gui.*
Per-user state lives under a platform-native <config-dir> resolved by ConfigLocationResolver (Linux: $XDG_CONFIG_HOME/jsignpdf or ~/.config/jsignpdf; Windows: %APPDATA%\JSignPdf; macOS: ~/Library/Application Support/JSignPdf). Override with JSIGNPDF_CONFIG_DIR. PropertyStoreFactory hands out PropertyProvider / AdvancedConfig instances backed by these files; tests construct them directly with a temp path instead of going through the singleton.
- Main config --
<config-dir>/config.properties-- last-used signing settings; passwords encrypted per-user. Backed byBasicSignerOptions/PropertyProvider. - Presets --
<config-dir>/presets/preset-<epoch-millis>.properties-- saved signing-option bundles. Display name lives inside aspreset.displayName. Loaded/managed byPresetManager. - Advanced config --
<config-dir>/advanced.properties-- app-global tweaks (font, certificate checks, relax SSL, PDF preview backends, default TSA hash). Two-layer overlay: user file → bundled defaults from/net/sf/jsignpdf/conf/advanced.default.properties. Read viaAppConfigstatic accessors; edited via the JavaFX File > Preferences... dialog (PreferencesController). - PKCS#11 config --
<config-dir>/pkcs11.cfg-- raw SunPKCS11 provider config at a fixed well-known location (the legacypkcs11config.pathkey was removed in 3.0.0). Loaded byPKCS11Utils.registerProvidersFromDefaultLocation()once at startup; restart required to re-register. - Legacy migration -- on first launch,
ConfigLocationResolver.resolveAndMigrate()copies~/.JSignPdftoconfig.properties. The original is left in place for downgrade safety.
- JUnit 4 - test sources under
jsignpdf/src/test/java/ - Signing tests (
signing/package): useSigningTestBasewhich creates temp PDFs dynamically - JavaFX UI tests (
fx/FxTranslationsTest): headless via Monocle, loads FXML with different locales and verifies node text
| Workflow | Trigger | Purpose |
|---|---|---|
pr-builder.yaml |
PR/push to master | mvn verify with Java 21 |
push-snapshots.yaml |
Push to master | Deploy SNAPSHOTs to Maven Central |
do-release.yml |
Manual dispatch | Irreversible half of a release: mvn release:prepare/perform → version-bump commits, git tag, Maven Central deploy of the library jars and the full/minimal distribution ZIPs (classified artifacts on com.github.kwart.jsign:jsignpdf-distribution, signed via the release profile). On success it chains to package-release.yml. Do not re-run on a packaging failure — re-dispatch package-release.yml instead. |
package-release.yml |
Auto (called by do-release.yml) or manual dispatch |
Resumable half: downloads the published full/minimal ZIPs from Maven Central (bounded retry for repo1 propagation), then per-platform jpackage matrix (windows-2022 / ubuntu-24.04 x2 / macos-14) → Flatpak matrix (x86_64 + aarch64) → publish (SHA-256 + SourceForge mirror + GitHub Release). The matrix packages the exact Central bits (scripts read the unpacked ZIP via JSIGNPDF_LIB_DIR), so re-dispatching it with the same release-version cleanly recovers a timed-out run without re-releasing. Native installers use Azul Zulu+FX 21 (java-package: jdk+fx) so JavaFX modules are available to jlink. No Intel-macOS build is shipped (Apple discontinued Intel; macos-13 retiring). See design-doc/3.1-separate-release-steps.md. |