Code

log: --show-signature
authorJunio C Hamano <gitster@pobox.com>
Tue, 18 Oct 2011 22:53:23 +0000 (15:53 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Oct 2011 23:30:18 +0000 (16:30 -0700)
This teaches the "log" family of commands to pass the GPG signature in the
commit objects to "gpg --verify" via the verify_signed_buffer() interface
used to verify signed tag objects. E.g.

    $ git show --show-signature -s HEAD

shows GPG output in the header part of the output.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
commit.c
commit.h
log-tree.c
revision.c
revision.h

index 4bff3cdaae882474164762ac62830c331b5eae00..93045a2cdae33426182c544e92ba0330133a10d7 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -848,6 +848,40 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
        return 0;
 }
 
+int parse_signed_commit(const unsigned char *sha1,
+                       struct strbuf *payload, struct strbuf *signature)
+{
+       unsigned long size;
+       enum object_type type;
+       char *buffer = read_sha1_file(sha1, &type, &size);
+       int in_header, saw_signature = -1;
+       char *line;
+
+       if (!buffer || type != OBJ_COMMIT)
+               goto cleanup;
+
+       line = buffer;
+       in_header = 1;
+       saw_signature = 0;
+       while (*line) {
+               char *next = strchrnul(line, '\n');
+               if (*next)
+                       next++;
+               if (in_header && !prefixcmp(line, gpg_sig_header)) {
+                       const char *sig = line + gpg_sig_header_len;
+                       strbuf_add(signature, sig, next - sig);
+                       saw_signature = 1;
+               } else {
+                       strbuf_add(payload, line, next - line);
+               }
+               if (*line == '\n')
+                       in_header = 0;
+               line = next;
+       }
+ cleanup:
+       free(buffer);
+       return saw_signature;
+}
 
 static const char commit_utf8_warn[] =
 "Warning: commit message does not conform to UTF-8.\n"
index 8c2419b51fcf28c79b8f788bfec19b54c95b293e..1885471b8b0325339d6bf0301eb5d8790d4136ab 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -177,4 +177,7 @@ extern int commit_tree(const char *msg, unsigned char *tree,
                struct commit_list *parents, unsigned char *ret,
                       const char *author, const char *sign_commit);
 
+extern int parse_signed_commit(const unsigned char *sha1,
+                              struct strbuf *message, struct strbuf *signature);
+
 #endif /* COMMIT_H */
index 24c295ea1dc91180b9685299f48812593162bdfe..f7b6976d9f16d5892d004005f87f30c23abd7394 100644 (file)
@@ -8,6 +8,7 @@
 #include "refs.h"
 #include "string-list.h"
 #include "color.h"
+#include "gpg-interface.h"
 
 struct decoration name_decoration = { "object names" };
 
@@ -395,6 +396,41 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
        *extra_headers_p = extra_headers;
 }
 
+static void show_signature(struct rev_info *opt, struct commit *commit)
+{
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
+       struct strbuf gpg_output = STRBUF_INIT;
+       int status;
+       const char *color, *reset, *bol, *eol;
+
+       if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
+               goto out;
+
+       status = verify_signed_buffer(payload.buf, payload.len,
+                                     signature.buf, signature.len,
+                                     &gpg_output);
+       if (status && !gpg_output.len)
+               strbuf_addstr(&gpg_output, "No signature\n");
+
+       color = diff_get_color_opt(&opt->diffopt,
+                                  status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
+       reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
+
+       bol = gpg_output.buf;
+       while (*bol) {
+               eol = strchrnul(bol, '\n');
+               printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
+                      *eol ? "\n" : "");
+               bol = (*eol) ? (eol + 1) : eol;
+       }
+
+ out:
+       strbuf_release(&gpg_output);
+       strbuf_release(&payload);
+       strbuf_release(&signature);
+}
+
 void show_log(struct rev_info *opt)
 {
        struct strbuf msgbuf = STRBUF_INIT;
@@ -502,6 +538,9 @@ void show_log(struct rev_info *opt)
                }
        }
 
+       if (opt->show_signature)
+               show_signature(opt, commit);
+
        if (!commit->buffer)
                return;
 
index c46cfaa3e4d2f06fd67ccd71c7ba47891796fd60..860a3128a39605d7d7216b9b728b7a6dd2d8a74c 100644 (file)
@@ -1381,6 +1381,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->show_notes = 1;
                revs->show_notes_given = 1;
                revs->notes_opt.use_default_notes = 1;
+       } else if (!strcmp(arg, "--show-signature")) {
+               revs->show_signature = 1;
        } else if (!prefixcmp(arg, "--show-notes=") ||
                   !prefixcmp(arg, "--notes=")) {
                struct strbuf buf = STRBUF_INIT;
index 3d64adad18e2c889b7a7b7367f99c239f958dc70..198bb95894a2c3a426e6842f894103ac3ea30d71 100644 (file)
@@ -89,6 +89,7 @@ struct rev_info {
                        show_merge:1,
                        show_notes:1,
                        show_notes_given:1,
+                       show_signature:1,
                        pretty_given:1,
                        abbrev_commit:1,
                        abbrev_commit_given:1,