]>
git.sthu.org Git - pgp-tools.git/blob - sig2dot/sig2dot
3 # sig2dot v0.29 (c) Darxus@ChaosReigns.com, released under the GPL
4 # Download from: http://www.chaosreigns.com/code/sig2dot/
5 # sig2dot v0.35-0.37 (c) 2005, 2006 Christoph Berg <cb@df7cb.de>
6 # Download from: http://ftp.debian.org/debian/pool/main/s/sig2dot/
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 # Parses output of "gpg --list-sigs" into a format
23 # suitable for rendering into a graph by graphviz
24 # (http://www.research.att.com/sw/tools/graphviz/) like so:
26 # $ gpg --list-sigs --keyring ./phillylinux.gpg | ./sig2dot.pl > phillylinux.dot
27 # $ neato -Tps phillylinux.dot > phillylinux.ps
28 # $ convert phillylinux.ps phillylinux.jpg
30 # Commandline options:
33 # Black and white / do not colorize.
36 # Render graph as it appeared on <date> (ignores more recent
37 # signatures). Date must be in the format "YYYY-MM-DD".
38 # Will also ignore keys that have since been revoked.
41 # Render all keys, even if they're not signed by any other key.
44 # Support localized output of GnuPG for unknown user IDs. For
45 # example, German users have to write (with sh quotation marks!)
46 # "[User-ID nicht gefunden]" if they use GnuPG with German
47 # messages. Default is "[User id not found]".
50 # Support localized output of GnuPG for revoked keys. For
51 # example, French users have to write "révoqué" if they use
52 # GnuPG with French messages. Default is "[revoked".
55 # Produces statistics file with number of signatures per node
66 # v0.9 2000-09-14 19:20 strip trailing whitespace from $id more cleanly
67 # v0.10 2000-09-14 19:33 skip revoked keys at the request of Peter Palfrader <ppalfrad@cosy.sbg.ac.at>
68 # v0.11 Nov 22 21:38 use ID for node name instead of username for uniqueness
69 # v0.12 Dec 15 16:20 use names instead of IDs again in stats.html
70 # v0.13 Jun 19 03:15 red is proportional to signatures
71 # v0.14 Jun 19 03:25 blue is proportional to other keys signed
72 # v0.15 Jun 20 17:16 fixed blue, green is proportional to ratio
73 # v0.16 Jun 20 18:55 uniqed %signedby
74 # v0.17 Jan 10 19:10 Use overlap=scale instead of fixed edge lengths. Requires new version of graphviz.
75 # v0.18 Jan 23 11:53 stats.html is now valid html (v.01 transitional)
76 # v0.23 May 3 18:52 bunch of new stuff, including -b flag (black & white), and fixes devision by zero error
77 # v0.24 May 3 18:59 add black outline to nodes, prettier (changed node attribute "color" to "fillcolor")
78 # v0.25 May 3 19:06 cleaned up anti- devision by zero code a little
79 # v0.26 May 4 00:08 strip all non-digit characters from $renderdate
80 # v0.27 May 10 00:23:49 2002 use {}'s to write 1 line per public key instead of one line per signature (much shorter)
81 # v0.28 Feb 13 2003 Change regex to handle option trust digit
82 # <kevin@rosenberg.net>
83 # v0.29 Feb 18 2003 Add -s option to optionally produce statistics file
84 # <kevin@rosenberg.net>
85 # v0.30 Feb 18 2003 Make --list-sigs regex more robust
86 # Marco Bodrato <bodrato@gulp.linux.it>
87 # v0.31 Jul 28 2003 Add -u option for localized output of GnuPG
88 # Marcus Frings <protagonist@gmx.net>
89 # further changes are documented in debian/changelog
97 my ( $stats , $color , $all , $not_found , $revokestr , $title );
101 getopts
( 'd:u:r:s:bahqvt:' , \
%opt );
106 Copyright (c) 2002 Darxus\ @ChaosReigns .com
107 Copyright (c) 2005, 2006 Christoph Berg <cb\ @df7cb .de>
114 gpg --list-sigs | $0 [-abdhqsuv] > sigs.dot
115 -a Graph all keys, even if they do not have a signature
116 -b Black and white / do not colorize.
117 -d YYYY-MM-DD Render graph as it appeared on date.
118 -h Print this help and exit.
120 -r sting key-is-revoked string (default: "[revoked").
121 -s stats.html Produces statistics file with number of signatures per node.
123 -u string user-id-not-found string (default: "[user id not found]").
124 -v Print version and exit.
134 $renderdate = $opt { d
};
135 print STDERR
"Printing from date: $renderdate . \n " ;
136 $renderdate =~ s/\D+//g ;
140 print STDERR
"Print statistics to $stats . \n " ;
145 print STDERR
"Black and White. \n " unless $opt { q
};
148 print STDERR
"Color. \n " unless $opt { q
};
157 $not_found = lc $opt { u
};
159 $not_found = "[user id not found]" ; # this changed from gpg 1.2 -> 1.4
163 $revokestr = lc $opt { r
};
165 $revokestr = "[revoked" ; # this changed from gpg 1.2 -> 1.4
171 $title = "Keyring Statistics" ;
174 my ( $owner , %name , %revlist , %sigstmp , %signedbytmp , %idlist , @names , %revs );
176 while ( my $line = <>)
181 #pub 1024D/807CAC25 2003-08-01 Michael Ablassmeier (abi) <abi#grinser.de>
182 #sig B3B2A12C 2004-01-28 [User id not found]
183 #sig 3 9456ADE2 2004-02-07 Michael Schiansky <michael#schiansky.de>
185 #pub 1024D/807CAC25 2003-08-01
186 #uid Michael Ablassmeier (abi) <abi#grinser.de>
187 #sig B3B2A12C 2004-01-28 [User ID not found]
188 #sig 3 9456ADE2 2004-02-07 Michael Schiansky <michael#schiansky.de>
191 if ( $line =~ m
#([\w]+)[ !\?][ \dLNPRTX]{0,8} +([^ ]+) +([^ ]+)(?: +"?([^<"]*))?#)
193 # " " -> "[ !\?]" (to use 'gpg --check-sigs|sig2dot.mio|springgraph|display')
194 # "[ \d]" -> "[ \dLRXP]" (signature attributes)
195 # "[^<]+" -> "[^<]*" (to recognise "pub" lines whitout a name)
196 # if ($line =~ m#([\w]+) [ \d]? +([^ ]+) +([^ ]+) +([^<]+)#)
197 # if ($line =~ m#([\w]+) +([^ ]+) +([^ ]+) +([^<]+)#)
206 if ( $type eq "pub" or $renderdate eq "" or $date <= $renderdate )
208 print STDERR
"Using: $line \n " unless $opt { q
};
209 # strip trailing whitespace more cleanly:
212 #Remove re: http://bugs.debian.org/202484
213 #$name =~ s/[^a-zA-Z \.0-9]/_/g; # handle non-7bit names
217 $id = ( split ( '/' , $id ))[ 1 ];
219 $idlist { $id } = 1 if ( index ( $name , $revokestr ) < 0 );
222 # remove comment field
223 $name { $id } = ( split ' \(' , $name )[ 0 ] if $name ; # gpg 1.4 fixup
226 if ( index ( $name , $revokestr ) >= 0 ) {
231 if ( $type eq "uid" ) {
232 $name { $owner } = $id ; # gpg 1.4 fixup
235 # unless (defined @{$sigs{$owner}})
237 # @{$sigs{$owner}} = ();
239 if ( $type eq "sig" and lc $name ne $not_found )
242 push ( @
{ $sigstmp { $owner }}, $id );
243 push ( @
{ $signedbytmp { $id }}, $owner );
245 if ( $all or $id ne $owner ) {
246 push ( @names , $id , $owner );
249 if ( $type eq "rev" and lc $name ne $not_found )
252 push ( @
{ $revs { $owner }}, $id );
253 #push (@{$revokedby{$id}},$owner);
257 print STDERR
"Skipping due to date: $line \n " ;
260 print STDERR
"Skipping due to regex: $line \n " if $line ne "" ;
264 my ( %sigs , %signedby );
266 for my $id ( sort { $sigstmp { $a } <=> $sigstmp { $b }} keys %sigstmp ) {
267 next if ( defined $revlist { $id });
268 foreach my $owner ( @
{ $signedbytmp { $id }}) {
269 next if ( defined $revlist { $owner });
271 foreach my $revid ( @
{ $revs { $owner }}) {
276 #$res = $revlist{$id};
277 if (( $revoke == 0 )) {
278 push ( @
{ $sigs { $owner }}, $id );
279 push ( @
{ $signedby { $id }}, $owner );
284 print "digraph \" $title \" { \n overlap=scale \n splines=true \n sep=.1 \n " ;
294 for my $owner ( sort { $sigs { $a } <=> $sigs { $b }} keys %sigs )
297 @saw { @
{ $sigs { $owner }}} = ();
298 @
{ $sigs { $owner }} = keys %saw ;
301 $signedby { $owner } ||= [];
302 @saw { @
{ $signedby { $owner }}} = ();
303 @
{ $signedby { $owner }} = keys %saw ;
306 $sigcount { $owner } = scalar ( @
{ $sigs { $owner }});
307 if ( $sigcount { $owner } > $maxsigcount )
309 $maxsigcount = $sigcount { $owner };
314 my ( $maxsignedbycount , $maxratio ) = ( 0 , 0 );
316 for my $owner ( sort { $signedby { $a } <=> $signedby { $b }} keys %signedby )
318 $signedbycount { $owner } = scalar ( @
{ $signedby { $owner }});
319 if ( $signedbycount { $owner } > $maxsignedbycount )
321 $maxsignedbycount = $signedbycount { $owner };
323 if ( $sigcount { $owner } and $sigcount { $owner } > 0 ) {
324 if ( $signedbycount { $owner } / $sigcount { $owner } > $maxratio )
326 $maxratio = $signedbycount { $owner } / $sigcount { $owner };
330 print "// $maxratio \n " ;
333 open ( STATS
, "> $stats " );
334 print STATS
"<!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.01 Transitional//EN \" \" http://www.w3.org/TR/html4/loose.dtd \" > \n <html><head><title> $title </title></head><body><table border=1> \n " ;
336 for my $owner ( sort { $sigcount { $b } <=> $sigcount { $a }} keys %sigs )
338 print STATS
"<tr><td> $name { $owner }<td> $sigcount { $owner }<td><img src= \" /images/pipe0.jpg \" height=15 width=" , $sigcount { $owner } * 20 , " alt= \" " . $chartchar x
$sigcount { $owner } . " \" > \n " ;
341 print STATS
"</table></body></html> \n " ;
345 print "node [style=filled] \n " ;
348 if (( not exists $sigcount { $id }) and ( not exists $signedbycount { $id }) and not $all ) {
351 next unless ( defined $idlist { $id });
354 my ( $red , $green , $blue ) = ( 0 , 1 /3, 1/ 3 );
355 if ( $sigcount { $id }) {
356 $red = $sigcount { $id } / $maxsigcount ;
358 if ( $sigcount { $id } && $maxratio != 0 )
360 $green = ( $signedbycount { $id } / $sigcount{$id} / $maxratio * .75 ) * 2 /3 + 1/ 3 ;
362 if ( $signedbycount { $id } and $maxsignedbycount != 0 ) {
363 $blue = ( $signedbycount { $id } / $maxsignedbycount) * 2/ 3 + 1 / 3 ;
366 my ( $hue , $saturation , $value ) = rgb2hsv
( $red , $green , $blue );
367 printf "// %d %d $red , $green , $blue \n " , $sigcount { $id } || 0 , $signedbycount { $id } || 0 ;
368 print " \" $id \" [fillcolor= \" $hue , $saturation , $value \" ,label= \" $name { $id } \" ] \n " ;
370 print " \" $id \" [label= \" $name { $id } \" ] \n " ;
373 #print "node [style=solid]\n";
375 for my $owner ( sort keys %sigs )
378 for my $id ( @
{ $sigs { $owner }})
382 print "} -> \" $owner \"\n " ;
387 # Converts rgb to hsv. All numbers are within range 0 to 1
388 # from http://twiki.org/cgi-bin/view/Codev/WebMap
390 my ( $r , $g , $b ) = @_ ;
391 my $max = maxof
( $r , maxof
( $g , $b ));
392 my $min = minof
( $r , minof
( $g , $b ));
397 $s = ( $max - $min ) / $max ;
402 my ( $rc , $gc , $bc , $diff );
404 $rc = ( $max - $r ) / $diff ;
405 $gc = ( $max - $g ) / $diff ;
406 $bc = ( $max - $b ) / $diff ;
408 $h = ( $bc - $gc ) / 6.0 ;
409 } elsif ( $g == $max ) {
410 $h = ( 2.0 + $rc - $bc ) / 6.0 ;
412 $h = ( 4.0 + $gc - $rc ) / 6.0 ;