From 2343c688b19d9bce4e75ada280be44043ad2dca2 Mon Sep 17 00:00:00 2001
From: Gunnar Wagenknecht
+ * Per spec of user.signingKey: this will be sent to the GPG program as is,
+ * i.e. can be anything supported by the GPG program.
+ *
+ * Note, if none was set or
+ * Note, the signature set here will change the payload of the commit, i.e.
+ * the output of {@link #build()} will include the signature. Thus, the
+ * typical flow will be:
+ * null
is specified a default will be
+ * obtained from the configuration.
+ * null
)
+ * @return {@code this}
+ * @since 5.3
+ */
+ public CommitCommand setSigningKey(String signingKey) {
+ checkCallable();
+ this.signingKey = signingKey;
+ return this;
+ }
+
+ /**
+ * Sets whether the commit should be signed.
+ *
+ * @param sign
+ * true
to sign, false
to not sign and
+ * null
for default behavior (read from
+ * configuration)
+ * @return {@code this}
+ * @since 5.3
+ */
+ public CommitCommand setSign(Boolean sign) {
+ checkCallable();
+ this.signCommit = sign;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
new file mode 100644
index 0000000000..eb5db6ad16
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018, Salesforce and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api.errors;
+
+/**
+ * Exception thrown when the configured gpg.format is not supported.
+ *
+ * @since 5.3
+ */
+public class UnsupportedSigningFormatException extends GitAPIException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor for UnsupportedGpgFormatException
+ *
+ * @param message
+ * error message
+ * @param cause
+ * a {@link java.lang.Throwable}
+ */
+ public UnsupportedSigningFormatException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor for UnsupportedGpgFormatException
+ *
+ * @param message
+ * error message
+ */
+ public UnsupportedSigningFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index a24cff1e49..9da7f15746 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -566,6 +566,7 @@ public class JGitText extends TranslationBundle {
/***/ public String onlyAlreadyUpToDateAndFastForwardMergesAreAvailable;
/***/ public String onlyOneFetchSupported;
/***/ public String onlyOneOperationCallPerConnectionIsSupported;
+ /***/ public String onlyOpenPgpSupportedForSigning;
/***/ public String openFilesMustBeAtLeast1;
/***/ public String openingConnection;
/***/ public String operationCanceled;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
index c30833d0a6..a30f042531 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -49,11 +49,15 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
+import java.text.MessageFormat;
import java.util.List;
+import org.eclipse.jgit.internal.JGitText;
+
/**
* Mutable builder to construct a commit recording the state of a project.
*
@@ -76,6 +80,8 @@ public class CommitBuilder {
private static final byte[] hcommitter = Constants.encodeASCII("committer"); //$NON-NLS-1$
+ private static final byte[] hgpgsig = Constants.encodeASCII("gpgsig"); //$NON-NLS-1$
+
private static final byte[] hencoding = Constants.encodeASCII("encoding"); //$NON-NLS-1$
private ObjectId treeId;
@@ -86,6 +92,8 @@ public class CommitBuilder {
private PersonIdent committer;
+ private GpgSignature gpgSignature;
+
private String message;
private Charset encoding;
@@ -155,6 +163,38 @@ public class CommitBuilder {
committer = newCommitter;
}
+ /**
+ * Set the GPG signature of this commit
+ *
+ *
+ *
null
to unset
+ * @since 5.3
+ */
+ public void setGpgSignature(GpgSignature newSignature) {
+ gpgSignature = newSignature;
+ }
+
+ /**
+ * Get the GPG signature of this commit.
+ *
+ * @return the GPG signature of this commit, maybe null
if the
+ * commit is not to be signed
+ * @since 5.3
+ */
+ public GpgSignature getGpgSignature() {
+ return gpgSignature;
+ }
+
/**
* Get the ancestors of this commit.
*
@@ -316,6 +356,13 @@ public class CommitBuilder {
w.flush();
os.write('\n');
+ if (getGpgSignature() != null) {
+ os.write(hgpgsig);
+ os.write(' ');
+ writeGpgSignatureString(getGpgSignature().toExternalString(), os);
+ os.write('\n');
+ }
+
if (getEncoding() != UTF_8) {
os.write(hencoding);
os.write(' ');
@@ -338,6 +385,50 @@ public class CommitBuilder {
return os.toByteArray();
}
+ /**
+ * Writes signature to output as per gpgsig
+ * header.
+ * + * CRLF and CR will be sanitized to LF and signature will have a hanging + * indent of one space starting with line two. + *
+ * + * @param in + * signature string with line breaks + * @param out + * output stream + * @throws IOException + * thrown by the output stream + * @throws IllegalArgumentException + * if the signature string contains non 7-bit ASCII chars + */ + static void writeGpgSignatureString(String in, OutputStream out) + throws IOException, IllegalArgumentException { + for (int i = 0; i < in.length(); ++i) { + char ch = in.charAt(i); + if (ch == '\r') { + if (i + 1 < in.length() && in.charAt(i + 1) == '\n') { + out.write('\n'); + out.write(' '); + ++i; + } else { + out.write('\n'); + out.write(' '); + } + } else if (ch == '\n') { + out.write('\n'); + out.write(' '); + } else { + // sanity check + if (ch > 127) + throw new IllegalArgumentException(MessageFormat + .format(JGitText.get().notASCIIString, in)); + out.write(ch); + } + } + } + /** * Format this builder's state as a commit object. * @@ -377,6 +468,10 @@ public class CommitBuilder { r.append(committer != null ? committer.toString() : "NOT_SET"); r.append("\n"); + r.append("gpgSignature "); + r.append(gpgSignature != null ? gpgSignature.toString() : "NOT_SET"); + r.append("\n"); + if (encoding != null && encoding != UTF_8) { r.append("encoding "); r.append(encoding.name()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java new file mode 100644 index 0000000000..663f850f0a --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018, Salesforce. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lib; + +import static java.nio.charset.StandardCharsets.US_ASCII; + +import java.io.Serializable; + +import org.eclipse.jgit.annotations.NonNull; + +/** + * A structure for holding GPG signature together with additional related data. + * + * @since 5.3 + */ +public class GpgSignature implements Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] signature; + + /** + * Creates a new instance with the specified signature + * + * @param signature + * the signature + */ + public GpgSignature(@NonNull byte[] signature) { + this.signature = signature; + } + + /** + * Format for Git storage. + *+ * This returns the ASCII Armor as per + * https://tools.ietf.org/html/rfc4880#section-6.2. + *
+ * + * @return a string of the signature ready to be embedded in a Git object + */ + public String toExternalString() { + return new String(signature, US_ASCII); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("nls") + public String toString() { + final StringBuilder r = new StringBuilder(); + + r.append("GpgSignature["); + r.append( + this.signature != null ? "length " + signature.length : "null"); + r.append("]"); + + return r.toString(); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java new file mode 100644 index 0000000000..e509c9783f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018, Salesforce. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lib; + +import org.eclipse.jgit.annotations.NonNull; + +/** + * Creates GPG signatures for Git objects. + * + * @since 5.3 + */ +public abstract class GpgSigner { + + private static GpgSigner defaultSigner; + + /** + * Get the default signer, ornull
.
+ *
+ * @return the default signer, or null
.
+ */
+ public static GpgSigner getDefault() {
+ return defaultSigner;
+ }
+
+ /**
+ * Set the default signer.
+ *
+ * @param signer
+ * the new default signer, may be null
to select no
+ * default.
+ */
+ public static void setDefault(GpgSigner signer) {
+ GpgSigner.defaultSigner = signer;
+ }
+
+ /**
+ * Signs the specified commit.
+ *
+ * + * Implementors should obtain the payload for signing from the specified + * commit via {@link CommitBuilder#build()} and create a proper + * {@link GpgSignature}. The generated signature must be set on the + * specified {@code commit} (see + * {@link CommitBuilder#setGpgSignature(GpgSignature)}). + *
+ *+ * Any existing signature on the commit must be discarded prior obtaining + * the payload via {@link CommitBuilder#build()}. + *
+ * + * @param commit + * the commit to sign (must not benull
and must be
+ * complete to allow proper calculation of payload)
+ * @param gpgSigningKey
+ * the signing key (passed as is to the GPG signing tool)
+ */
+ public abstract void sign(@NonNull CommitBuilder commit,
+ String gpgSigningKey);
+
+}
--
cgit v1.2.3