From 6b2a27f3a60e8c92079f14e5240ee8c353ccfa35 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 24 Sep 2024 14:43:54 +0200 Subject: [PATCH] [MGPG-136] Windows passphrase corruption (#120) Since 3.2.0 version we always appended "line separator" to passphrase unless it itself ended with one. But, this caused problem on Windows, as (our assumption is) that GPG uses binary read of STDIN, and on Windows "line separator" is "\r\n", while GPG handles "\n" only, making passphrase corrupted by presence of unwanted "\r". --- https://issues.apache.org/jira/browse/MGPG-136 --- .../maven/plugins/gpg/AbstractGpgMojo.java | 17 +++++++++++++++++ .../maven/plugins/gpg/AbstractGpgSigner.java | 6 ++++++ .../org/apache/maven/plugins/gpg/GpgSigner.java | 7 ++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgMojo.java b/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgMojo.java index a99ce6c..e1c9a23 100644 --- a/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgMojo.java +++ b/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgMojo.java @@ -270,6 +270,22 @@ public abstract class AbstractGpgMojo extends AbstractMojo { @Parameter(property = "gpg.bestPractices", defaultValue = "false") private boolean bestPractices; + /** + * Whether to terminate the passphrase with LF character or not, as on some systems and some GPG executable combinations + * lack of trailing LF may cause GPG to not detect passphrase on STDIN. Since 3.2.0 it was always appended, unless + * passphrase itself ended with it. Note: before 3.2.7 the "line separator" was used for termination, that on + * other hand caused issues on Windows, where line separator is CRLF while GPG handles LF only. + * This parameter affects ONLY the GPG signer, not the BC signer. + *

+ * By default, this parameter is {@code true}. + * + * @since 3.2.7 + * @see MGPG-99 + * @see MGPG-136 + */ + @Parameter(property = "gpg.terminatePassphrase", defaultValue = "true") + private boolean terminatePassphrase; + /** * Current user system settings for use in Maven. * @@ -345,6 +361,7 @@ protected AbstractGpgSigner newSigner(MavenProject mavenProject) throws MojoFail signer.setPublicKeyring(publicKeyring); signer.setLockMode(lockMode); signer.setArgs(gpgArguments); + signer.setTerminatePassphrase(terminatePassphrase); // "new way": env prevails String passphrase = diff --git a/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgSigner.java b/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgSigner.java index 0c1a9a4..56004ae 100644 --- a/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgSigner.java +++ b/src/main/java/org/apache/maven/plugins/gpg/AbstractGpgSigner.java @@ -46,6 +46,8 @@ public abstract class AbstractGpgSigner { protected String passphrase; + protected boolean terminatePassphrase; + private File outputDir; private File buildDir; @@ -98,6 +100,10 @@ public void setPassPhrase(String s) { passphrase = s; } + public void setTerminatePassphrase(boolean b) { + this.terminatePassphrase = b; + } + public void setOutputDirectory(File out) { outputDir = out; } diff --git a/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java b/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java index 98d5331..d63bd5f 100644 --- a/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java +++ b/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java @@ -112,9 +112,10 @@ protected void generateSignatureForFile(File file, File signature) throws MojoEx cmd.createArg().setValue("--passphrase-fd"); cmd.createArg().setValue("0"); - // Prepare the input stream which will be used to pass the passphrase to the executable - if (!passphrase.endsWith(System.lineSeparator())) { - in = new ByteArrayInputStream((passphrase + System.lineSeparator()).getBytes()); + // Prepare the STDIN stream which will be used to pass the passphrase to the executable + // but obey terminatePassphrase: append LF if asked for + if (terminatePassphrase && !passphrase.endsWith("\n")) { + in = new ByteArrayInputStream((passphrase + "\n").getBytes()); } else { in = new ByteArrayInputStream(passphrase.getBytes()); }