Last active
October 3, 2017 11:41
-
-
Save jow-/3f9576545836b4d9a7d8ba38af15d1c4 to your computer and use it in GitHub Desktop.
A Perl script to update the key signature listing of https://lede-project.org/docs/user-guide/signatures
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment