#!/usr/bin/perl use Term::ReadLine; sub commit { unlink "pwd.gpg.old" or die "Couldn't unlink: $!"; rename "pwd.gpg", "pwd.gpg.old" or die "Couldn't rename: $!"; open PWD, "|gpg --symmetric --force-mdc --cipher-algo AES256 --output pwd.gpg" or die "Couldn't encrypt: $!"; for $i (keys %pw) { print PWD "$i\t$pw{$i}{pw}\t$pw{$i}{us}\n"; } close PWD or warn "Couldn't write pwd: $!"; $changed = 0; } sub randpass { return join("", @chars[map{rand @chars} (1..8)]); } sub xclip { open(XCLIP, "|/usr/X11R6/bin/xclip") or warn("No xclip - use .p\n"), return; print XCLIP $_[0]; close XCLIP; } $ENV{PATH} = "/bin:/usr/bin"; umask 077; @achars = ("A" .. "Z", "a" .. "z", "0" .. "9"); for($i = 33; $i <= 126; $i++) { #alphanum and punct, no space @apchars[$i-33] = chr $i; } @chars =@apchars; chdir "$ENV{HOME}/pw" or die "Couldn't cd: $!"; open PWD, "gpg --output - --decrypt pwd.gpg|" or die "Couldn't decrypt: $!"; while() { chomp; /^([^\t]+)\t([^\t]+)\t([^\t]+)$/ or warn "Malformed line $.: $_\n"; $pw{$1}{pw} = $2; $pw{$1}{us} = $3; } close PWD; $term = new Term::ReadLine "pw"; $attribs = $term->Attribs; $attribs->{completion_entry_function} = $attribs->{list_completion_function}; $attribs->{completion_word} = [keys %pw]; while(defined($_ = $term->readline("> "))) { chomp; if(/^\/(.*)/) { $s = $1; for $i (keys %pw) { print "$pw{$i}{us}\t$i\n" if $i =~ /$s/; } } elsif(/^\.(.)/) { if($1 eq "n") { /^\.n\t([^\t]+)\t([^\t]+)\t([^\t]+)$/ or warn(".n [tab] account [tab] password [tab] username\n"), next; $changed++; if($2 eq "R") { $p = randpass; xclip($p); } else { $p = $2; } $pw{$1}{pw} = $p; $pw{$1}{us} = $3; } elsif($1 eq "d") { /^\.d\s+([^\t]+?)\s*$/ or warn(".d account\n"), next; warn("No account $1\n"), next unless exists $pw{$1}; $changed++; delete $pw{$1}; } elsif($1 eq "p") { /^\.p\s+([^\t]+?)\s*$/ or warn(".p account\n"), next; warn("No account $1\n"), next unless exists $pw{$1}; print "$pw{$1}{us}\t$pw{$1}{pw}\n"; } elsif($1 eq "x") { /^\.x\s+([^\t]+?)\s*$/ or warn(".x account\n"), next; warn("No account $1\n"), next unless exists $pw{$1}; xclip($pw{$1}{pw}); } elsif($1 eq "c") { commit; } elsif($1 eq "r") { xclip(randpass); } elsif($1 eq "R") { print randpass, "\n"; } elsif($1 eq "a") { @chars =@achars; } elsif($1 eq "A") { @chars =@apchars; } elsif($1 eq "h") { print "\txclip account password and exit\n/\tsearch accounts\n.n\t\tnew account\n.d\t\tdelete account\n.p\t\tprint account\n.x\t\txclip account password\n.c\t\tcommit changes\n.r\t\txclip random password\n.R\t\tprint random password\n.a\t\tswitch to alphanum\n.A\t\tswitch to alphanum and punct\n.h\t\thelp\n"; } else { warn "Bad command .$1\n"; } } else { /^ *([^\t]+?)\s*$/ or next; $s = $1; for $i (keys %pw) { $p = $pw{$i}{pw}, last if $i eq $s; $p = $pw{$i}{pw} if $i =~ /\Q$s/; } warn("Couldn't find account $s\n"), next unless length $p; xclip($p); commit if $changed; sleep 10; xclip(""); exit; } } continue { $attribs->{completion_word} = [keys %pw]; } commit if $changed;