#!/usr/bin/perl # sig2dot v0.17 (c) Darxus@ChaosReigns.com, released under the GPL # Download from: http://www.chaosreigns.com/debian-keyring # # Parses the (gpg) debian-keyring # (http://www.debian.org/Packages/unstable/misc/debian-keyring.html) to a format # suitable for use by dot or neato (package name graphviz, # http://www.research.att.com/sw/tools/graphviz/) like so: # # gpg --with-colons --check-sigs --keyring /usr/share/keyrings/debian-keyring.gpg | ./sig2dot.pl > debian-keyring.dot # neato -Tps debian-keyring.dot > debian-keyring.neato.dot.ps # dot -Tps debian-keyring.dot > debian-keyring.dot.dot.ps # # v0.9 2000-09-14 19:20 strip trailing whitespace from $id more cleanly # v0.10 2000-09-14 19:33 skip revoked keys at the request of Peter Palfrader # v0.11 Nov 22 21:38 use ID for node name instead of username for uniqueness # v0.12 Dec 15 16:20 use names instead of IDs again in stats.html # v0.13 Jun 19 03:15 red is proportional to signatures # v0.14 Jun 19 03:25 blue is proportional to other keys signed # v0.15 Jun 20 17:16 fixed blue, green is proportional to ratio # v0.16 Jun 20 18:55 uniqed %signedby # v0.17 Jan 10 19:10 Use overlap=scale instead of fixed edge lengths. Requires graphviz v1.7.8. # v0.18? 2003-07-11 Jeremy Portzer patch to use --with-colons input while ($line = ) { chomp $line; if ($line =~ /^(pub|sig)/ ) #types we can process { @fields = split(/:/,$line); $type = $fields[0]; $id = $fields[4]; $name = $fields[9]; #strip off leading 8 bytes of key ID that we don't need $id = substr($id,8); # strip trailing whitespace more cleanly: $name =~ s/\s+$//g; if ($type eq "pub") { $owner = $id; } print STDERR "Processing owner,type,id,name : $owner,$type,$id,$name\n"; $name{$id} = $name; # skip revoked keys next if ($owner eq '[revoked]'); if ($type eq "sig" and $id ne $owner and $name ne '[User id not found]') { push (@{$sigs{$owner}},$id); push (@{$signedby{$id}},$owner); push (@names,$id,$owner); } } else { print STDERR "Skipping: $line\n"; } } print "digraph \"debian-keyring\" {\noverlap=scale\nsplines=true\nsep=.1\n"; undef %saw; @saw{@names} = (); @names = keys %saw; undef %saw; for $owner (sort {$sigs{$a} <=> $sigs{$b}} keys %sigs) { undef %saw; @saw{@{$sigs{$owner}}} = (); @{$sigs{$owner}} = keys %saw; undef %saw; undef %saw; @saw{@{$signedby{$owner}}} = (); @{$signedby{$owner}} = keys %saw; undef %saw; $sigcount{$owner} = scalar(@{$sigs{$owner}}); if ($sigcount{$owner} > $maxsigcount) { $maxsigcount = $sigcount{$owner}; } $signedbycount{$owner} = scalar(@{$signedby{$owner}}); if ($signedbycount{$owner} > $maxsignedbycount) { $maxsignedbycount = $signedbycount{$owner}; } if ($signedbycount{$owner} / $sigcount{$owner} > $maxratio) { $maxratio = $signedbycount{$owner} / $sigcount{$owner}; } } print "//$maxratio\n"; open (STATS,">stats.html"); print STATS "\n"; for $owner (sort {$sigcount{$b} <=> $sigcount{$a}} keys %sigs) { print STATS "
$name{$owner}$sigcount{$owner}\n"; } print STATS "
\n"; close STATS; print "node [style=filled]\n"; for $id (@names) { $red = $sigcount{$id} / $maxsigcount; #$green = .25; $green = $signedbycount{$id} / $sigcount{$id} / $maxratio * .75; $blue = $signedbycount{$id} / $maxsignedbycount; ($hue,$saturation,$value) = rgb2hsv($red,$green,$blue); #print "//$red,$green,$blue\n"; print "//$sigcount{$id} $signedbycount{$id} $red,$green,$blue\n"; print "\"$id\" [color=\"$hue,$saturation,$value\",label=\"$name{$id}\"]\n"; } #print "node [style=solid]\n"; for $owner (sort keys %sigs) { for $id (@{$sigs{$owner}}) { print "\"$id\" -> \"$owner\"\n"; } } print "}\n"; # Converts rgb to hsv. All numbers are within range 0 to 1 # from http://twiki.org/cgi-bin/view/Codev/WebMap sub rgb2hsv { my ($r, $g ,$b) = @_; my $max = maxof($r, maxof($g, $b)); my $min = minof($r, minof($g, $b)); $v = $max; if ($max > 0.0) { $s = ($max - $min) / $max; } else { $s = 0; } if ($s > 0.0) { my ($rc, $gc, $bc, $diff); $diff = $max - $min; $rc = ($max - $r) / $diff; $gc = ($max - $g) / $diff; $bc = ($max - $b) / $diff; if ($r == $max) { $h = ($bc - $gc) / 6.0; } elsif ($g == $max) { $h = (2.0 + $rc - $bc) / 6.0; } else { $h = (4.0 + $gc - $rc) / 6.0; } } else { $h = 0.0; } if ($h < 0.0) { $h += 1.0; } return ($h, $s, $v); } sub maxof { my ($a, $b) = @_; return $a>$b?$a:$b; } sub minof { my ($a, $b) = @_; return $a<$b?$a:$b; }