add a Perl script to update the key signature listing
authorJo-Philipp Wich <jo@mein.io>
Sat, 23 Dec 2017 10:59:54 +0000 (11:59 +0100)
committerJonas Gorski <jonas.gorski@gmail.com>
Sat, 23 Dec 2017 11:13:35 +0000 (12:13 +0100)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
make-signatures.pl [new file with mode: 0755]

diff --git a/make-signatures.pl b/make-signatures.pl
new file mode 100755 (executable)
index 0000000..dc6c3c3
--- /dev/null
@@ -0,0 +1,280 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use locale;
+
+use POSIX qw(mktime strftime setlocale LC_COLLATE);
+
+setlocale(LC_COLLATE, "en_US.UTF-8");
+
+my $page = 'https://lede-project.org/docs/user-guide/signatures';
+
+my @keytypes = (
+       undef,
+       'RSA',
+       'RSA, encrypt only',
+       'RSA, sign only',
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       undef,
+       'Elgamal, encrypt only',
+       'DSA',
+       'EC',
+       'ECDSA',
+       'Elgamal'
+);
+
+sub format_title {
+       my ($key) = @_;
+
+       if ($key->{is_system_key}) {
+               return $key->{comment};
+       }
+
+       return sprintf 'Public key of %s', $key->{name};
+}
+
+sub format_keytype {
+       my ($key, $is_subkey) = @_;
+
+       my $type = $key->{$is_subkey ? 'stype' : 'type'};
+       my $size = $key->{$is_subkey ? 'ssize' : 'size'};
+
+       my ($d, $m, $y, $s);
+
+       if (defined($size) && $size > 0) {
+               $s = sprintf '%d Bit %s', $size, $keytypes[$type];
+       }
+       else {
+               $s = $keytypes[$type];
+       }
+
+       (undef, undef, undef, $d, $m, $y) =
+               localtime $key->{$is_subkey ? 'sctime' : 'ctime'};
+
+       $s .= sprintf ', created %04d-%02d-%02d', $y + 1900, $m + 1, $d;
+
+       (undef, undef, undef, $d, $m, $y) =
+               localtime $key->{$is_subkey ? 'setime' : 'etime'};
+
+       if ($d && $m && $y) {
+               $s .= sprintf ', expires %04d-%02d-%02d', $y + 1900, $m + 1, $d;
+       }
+
+       return $s;
+}
+
+sub format_fingerprint {
+       my ($key, $is_subkey) = @_;
+
+       my $fprint = $key->{$is_subkey ? 'sfprint' : 'fprint'};
+       my (@fields) = $fprint =~ m!([A-F0-9]{4})!g;
+
+       return join(' ', @fields[0..4]) . '  ' . join(' ', @fields[5..9]);
+}
+
+sub format_download {
+       my ($key) = @_;
+
+       my $mtime = $key->{ctime};
+
+       if (open GIT, '-|', qw(git log -1 --format=%ct --), $key->{filename}) {
+               if (defined(my $line = readline GIT)) {
+                       chomp $line;
+                       $mtime = $line;
+               }
+               close GIT;
+       }
+
+       my $ts = strftime '%F %T %z', gmtime $mtime;
+
+       return sprintf
+               "[[https://git.lede-project.org/?p=keyring.git;a=history;f=%s|Last change: %s]] | " .
+               "[[https://git.lede-project.org/?p=keyring.git;a=blob_plain;f=%s|Download]]\n"  ,
+               $key->{filename}, $ts, $key->{filename};
+}
+
+sub parse_timestamp {
+       my ($s) = @_;
+
+       if ($s =~ m!^(\d\d\d\d)-(\d\d)-(\d\d)$!) {
+               return mktime(0, 0, 0, $3 + 0, $2 - 1, $1 - 1900);
+       }
+
+       return int $s;
+}
+
+
+my $markup_template = '';
+
+if (open RAW, '-|', 'curl', '-s', "$page?do=export_raw") {
+       local $/;
+       $markup_template = readline RAW;
+       close RAW;
+}
+
+
+my @pubkeys;
+
+if (open KEYS, '-|', qw(find gpg/ -type f -name *.asc -print)) {
+       while (defined(my $file = readline KEYS)) {
+               chomp $file;
+               if (open GPG, '-|', qw(gpg --with-fingerprint --with-fingerprint --with-colons), $file) {
+                       my %data;
+
+                       while (defined(my $line = readline GPG)) {
+                               chomp $line;
+                               my @fields = split ':', $line;
+                               if ($fields[0] eq 'uid' && !exists $data{name}) {
+                                       ($data{name}, $data{comment}, $data{email}) =
+                                               $fields[9] =~ m!^([^()]+)(?: \((.+?)\))? <(.+)>$!;
+                               }
+                               elsif ($fields[0] eq 'pub') {
+                                       $data{size} = int $fields[2];
+                                       $data{type} = int $fields[3];
+                                       $data{eid} = $fields[4];
+                                       $data{ctime} = parse_timestamp($fields[5]);
+                                       $data{etime} = $fields[6] ? parse_timestamp($fields[6]) : 0;
+                                       if ($fields[9] && !exists $data{name}) {
+                                               ($data{name}, $data{comment}, $data{email}) =
+                                                       $fields[9] =~ m!^([^()]+)(?: \((.+?)\))? <(.+)>$!;
+                                       }
+                               }
+                               elsif ($fields[0] eq 'sub') {
+                                       $data{ssize} = int $fields[2];
+                                       $data{stype} = int $fields[3];
+                                       $data{seid} = $fields[4];
+                                       $data{sctime} = parse_timestamp($fields[5]);
+                                       $data{setime} = $fields[6] ? parse_timestamp($fields[6]) : 0;
+                               }
+                               elsif ($fields[0] eq 'fpr') {
+                                       $data{exists($data{stype}) ? 'sfprint' : 'fprint'} = $fields[9];
+                               }
+                       }
+
+                       close GPG;
+
+                       $data{filename} = $file;
+                       $data{is_system_key} =
+                               (index($data{email}, 'lede-project.org') >= 0) ||
+                               (index($data{email}, 'lists.infradead.org') >= 0);
+
+                       push @pubkeys, \%data;
+               }
+       }
+
+       close KEYS;
+}
+
+my $gpg_markup = '';
+
+foreach my $key (sort {
+       !$a->{is_system_key} <=> !$b->{is_system_key} ||
+       $a->{name} cmp $b->{name}
+} @pubkeys) {
+
+       $gpg_markup .= sprintf "---\n\n=== %s ===\n\n",
+               format_title($key);
+
+       $gpg_markup .= sprintf "User ID: **%s** <%s>\\\\\n",
+               $key->{name}, $key->{email};
+
+       $gpg_markup .= sprintf "Public Key: 0x%s**%s** (%s)\\\\\n",
+               substr($key->{eid}, 0, 8), substr($key->{eid}, 8),
+               format_keytype($key, 0);
+
+       $gpg_markup .= sprintf "Fingerprint: ''%%%%%s%%%%''\\\\\n",
+               format_fingerprint($key, 0);
+
+       if (exists $key->{stype}) {
+               $gpg_markup .= sprintf "Signing Subkey: 0x%s **%s** (%s)\\\\\n",
+                       substr($key->{seid}, 0, 8), substr($key->{seid}, 8),
+                       format_keytype($key, 1);
+
+               $gpg_markup .= sprintf "Fingerprint: ''%%%%%s%%%%''\\\\\n",
+                       format_fingerprint($key, 1);
+       }
+
+       $gpg_markup .= sprintf "%s\n", format_download($key);
+}
+
+
+my @usignkeys;
+
+if (open KEYS, '-|', qw(find usign/ -type f -name *[0-9a-f] -print)) {
+       while (defined(my $file = readline KEYS)) {
+               chomp $file;
+
+               if (open USIGN, '<', $file) {
+                       my %data;
+
+                       while (defined(my $line = readline USIGN)) {
+                               chomp $line;
+
+                               if ($line =~ m!^untrusted comment: (.+)$!) {
+                                       $data{comment} = $1;
+                               }
+                               else {
+                                       $data{key} = $line;
+                               }
+                       }
+
+                       close USIGN;
+
+                       $file =~ m!/([0-9a-f]{16})$!;
+
+                       $data{id} = $1;
+                       $data{filename} = $file;
+
+                       push @usignkeys, \%data;
+               }
+       }
+
+       close KEYS;
+}
+
+my $usign_markup = '';
+
+foreach my $key (sort { $a->{comment} cmp $b->{comment} } @usignkeys) {
+       $usign_markup .= sprintf "---\n\n=== %s ===\n\n",
+               $key->{comment};
+
+       $usign_markup .= sprintf "  * Key-ID: ''%%%%%s%%%%''\n",
+               $key->{id};
+
+       $usign_markup .= sprintf "  * Key-Data: ''%%%%%s%%%%''\n\n",
+               $key->{key};
+
+       $usign_markup .= sprintf "%s\n",
+               format_download($key);
+}
+
+
+$markup_template =~ s!
+       ( /\*\sBEGIN\sGPG\sKEYS\s\*/ )
+       .+
+       ( /\*\sEND\sGPG\sKEYS\s\*/ )
+!
+       $1 . "\n\n" . $gpg_markup . $2;
+!esx;
+
+$markup_template =~ s!
+       ( /\*\sBEGIN\sUSIGN\sKEYS\s\*/ )
+       .+
+       ( /\*\sEND\sUSIGN\sKEYS\s\*/ )
+!
+       $1 . "\n\n" . $usign_markup . $2;
+!esx;
+
+
+print $markup_template;