Skip to content

Read passwords from stdin with --enable-stdin-passwords (closes #7)#357

Merged
kwart merged 6 commits intomasterfrom
issue/7
Apr 21, 2026
Merged

Read passwords from stdin with --enable-stdin-passwords (closes #7)#357
kwart merged 6 commits intomasterfrom
issue/7

Conversation

@kwart
Copy link
Copy Markdown
Member

@kwart kwart commented Apr 21, 2026

Summary

Lets the CLI read password values from standard input (or from an interactive console with no-echo) instead of taking them verbatim on the command line. Addresses #7 — a daemon feeding JSignPdf from stdin no longer has to expose keystore passwords via /proc/<pid>/cmdline or shell history.

Opt in with the new --enable-stdin-passwords flag, then use - as the value of any of the six password options:

Short Long
-ksp --keystore-password
-kp --key-password
-opwd --owner-password
-upwd --user-password
-tscp --tsa-cert-password
-tsp --tsa-password

When multiple options use -, stdin lines are consumed in a fixed canonical order (the order in the table above) regardless of the order the options appear on the CLI. Before each read, a progress line such as [jsignpdf] Reading password for --keystore-password (1/2) from stdin... is written to stderr so the operator can verify the order matches the pipe. -q / --quiet suppresses the progress line.

When System.console() is non-null (interactive terminal), the read switches to Console.readPassword(...) for a prompted, no-echo input.

Design

Full design notes: design-doc/3.0.0-stdin-passwords.md.

  • New boolean flag, long-only: --enable-stdin-passwords.
  • Sentinel is exactly - (one hyphen). Any other value — -abc, abc-, empty, ... — is treated as a literal password exactly as today. Commons-CLI intercepts a bare -- as its end-of-options marker, so that specific string cannot be used as a literal password via -ksp --; noted in the user guide.
  • Backwards compatible. Without the flag, - is still accepted as a literal password value exactly as before. JSignPdf emits a one-time warning per affected option naming the flag ([jsignpdf] Warning: --keystore-password value is '-'. Did you mean to pass --enable-stdin-passwords to read it from stdin? Using '-' as the literal password.), suppressed by -q.
  • IO seam for tests: package-private setPasswordReader(StdinPasswordReader) / setWarningOut(PrintStream) on SignerOptionsFromCmdLine. Production default is a StdinPasswordReader wired to System.in / System.console() / System.err.
  • EOF or IO error while reading a sentinel password becomes a ParseException that names the option, handled by the existing parseCommandLine error path in Signer.

Examples

Piped daemon, keystore + TSA auth:

{ printf '%s\n' "$KS_PASSWORD"; printf '%s\n' "$TSA_PASSWORD"; } \
  | java -jar JSignPdf.jar --enable-stdin-passwords \
      -kst PKCS12 -ksf keystore.p12 -ksp - -ka mykey \
      -ts https://tsa.example/ -tsu tsauser -tsp - \
      -d out/ input.pdf

Interactive:

$ java -jar JSignPdf.jar --enable-stdin-passwords -ksf keystore.p12 -ksp - -ka mykey input.pdf
Enter password for --keystore-password: ****

Changes

  • New StdinPasswordReader (jsignpdf/src/main/java/net/sf/jsignpdf/StdinPasswordReader.java): injectable BufferedReader / Console / PrintStream / quiet flag, readNext(longName, index, total) emits the progress line and blocks on input.
  • SignerOptionsFromCmdLine: registered the new flag, refactored the six if (line.hasOption(ARG_…_PWD)) setXxx(...) blocks into a single resolvePasswords(line) pass at the end of loadCmdLine() that walks the options in canonical order, reads from stdin when the flag is set, warns and falls back to literal - otherwise.
  • Constants: added ARG_ENABLE_STDIN_PWDS_LONG and STDIN_PWD_SENTINEL.
  • English messages.properties: new hlp.enableStdinPasswords; appended the stdin suffix to the six password help strings. Other locales stay in sync via Weblate.
  • Docs: new "Reading passwords from standard input" section in website/docs/JSignPdf.adoc (the authoritative user guide); new bullet in distribution/doc/release-notes/3.0.0.md; new section in README.md.
  • AGENTS.md: new "Key Documentation Artifacts" section that flags JSignPdf.adoc as the authoritative user guide that must stay feature-complete.

Test plan

  • mvn test in jsignpdf/ — 104/104 passing, including 8 unit tests in StdinPasswordReaderTest and 15 integration tests in SignerOptionsFromCmdLineTest.
  • Live pipe smoke: echo keystorepass | java -jar … --enable-stdin-passwords -lk -kst PKCS12 -ksf src/test/resources/test-keystore.p12 -ksp - successfully lists the keystore aliases after consuming the piped password.
  • Live warning smoke: same invocation without --enable-stdin-passwords emits the one-shot warning naming --keystore-password and --enable-stdin-passwords, then falls back to using - as the literal password.
  • Quiet mode: adding -q suppresses the warning.
  • --help output renders the new flag and the updated password help strings.
  • Manual interactive check on a real TTY (prompt appears, no echo) — worth a quick sanity run before tagging Beta.
  • Manual check on Windows cmd.exe / PowerShell for line-ending handling — worth a quick sanity run before tagging Beta.

Closes #7.

@kwart kwart merged commit 6ab201e into master Apr 21, 2026
1 check passed
@kwart kwart deleted the issue/7 branch April 21, 2026 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Read pasword fom sdtin

1 participant