From c9b94ac51383501ea80e0485cba4f891dbcce3fa Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Sat, 2 Apr 2011 19:24:39 +0200 Subject: Switch to App::Raps2. Still missing documentation, errorchecking and tests --- bin/raps2 | 325 ++------------------------------------------------------------ 1 file changed, 7 insertions(+), 318 deletions(-) (limited to 'bin/raps2') diff --git a/bin/raps2 b/bin/raps2 index 763b1d8..c810fec 100755 --- a/bin/raps2 +++ b/bin/raps2 @@ -7,329 +7,18 @@ use warnings; use 5.010; use autodie; -use Crypt::CBC; -use Crypt::Eksblowfish; -use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 de_base64); -use File::Path qw(make_path); -use File::Slurp qw(slurp write_file); -use POSIX; - -my $VERSION = '0.1'; - -my %state = ( - cost => 12, - salt => new_salt(), -); +use App::Raps2; +my $raps2 = App::Raps2->new(); my ($action, @args) = @ARGV; -sub cmd_add { - my ($name) = @_; - my $init = get_xdg_config_file('init'); - my $store = get_xdg_data_file($name); - my $pass; - - if (-e $store) { - die("This password name already exists\n"); - } - - my $cipher; - my $password; - - $password = get_password(); - undef %state; - load_state_from($init); - $state{'salt'} = new_salt(); - $state{'cost'} //= 12; - - $state{'url'} = read_input( - prefix => 'URL' - ); - $state{'login'} = read_input( - prefix => 'Login' - ); - $state{'extra'} = read_input( - prefix => 'Extra' - ); - $pass = read_input( - prefix => 'Password', - invisible => 1, - verify => 1, - ); - - $cipher = setup_cipher($password); - - $state{'hash'} = $cipher->encrypt_hex($pass); - - save_state_to($store); - - return; -} - -sub cmd_dump { - my ($name) = @_; - my $store = get_xdg_data_file($name); - my $password; - my $cipher; - - if (not -e $store) { - die("No such password\n"); - } - - $password = get_password(); - load_state_from($store); - $cipher = setup_cipher($password); - - printf( - "%-8s : %s\n" x 4, - 'URL' , $state{'url'}, - 'Login' , $state{'login'}, - 'Extra' , $state{'extra'} // q{}, - 'Password', $cipher->decrypt_hex($state{'hash'}), - ); - - return; -} - -sub cmd_get { - my ($name) = @_; - my $store = get_xdg_data_file($name); - my $password; - my $cipher; - - if (not -e $store) { - die("No such password\n"); - } - - $password = get_password(); - load_state_from($store); - - $cipher = setup_cipher($password); - - to_clipboard($cipher->decrypt_hex($state{'hash'})); - - return; -} - -sub cmd_info { - my ($name) = @_; - my $store = get_xdg_data_file($name); - - if (not -e $store) { - die("No such password\n"); - } - - load_state_from($store); - - printf( - "%-8s : %s\n" x 3, - 'URL' , $state{'url'}, - 'Login', $state{'login'}, - 'Extra', $state{'extra'} // q{}, - ); - return; -} - -sub cmd_list { - opendir(my $dh, get_xdg_data_file()); - my @entries = grep { /^[^.]/ } readdir($dh); - closedir($dh); - - for my $file (sort @entries) { - say $file; - } -} - -sub create_dot_dirs { - make_path(get_xdg_config_file()); - make_path(get_xdg_data_file()); - return; -} - -sub create_pass { - my ($passfile) = @_; - my $pass; - my $hash; - - say 'raps2 was never run before. Please set master password first.'; - $pass = read_input( - prefix => 'Password', - invisible => 1, - verify => 1, - ); - - $hash = en_base64(bcrypt_hash({ - key_nul => 1, - cost => $state{'cost'}, - salt => $state{'salt'}, - }, $pass)); - write_file( - $passfile, - "cost $state{cost}\n", - "salt $state{salt}\n", - "hash $hash\n", - ); - - return $pass; -} - -sub get_password { - my $pass; - my $passfile = get_xdg_config_file('password'); - - if (not -e $passfile) { - return create_pass($passfile); - } - - load_state_from($passfile); - $pass = read_input( - prefix => 'Master password', - invisible => 1, - ); - if (en_base64(bcrypt_hash({ - key_nul => 1, - cost => $state{'cost'}, - salt => $state{'salt'}, - }, $pass)) ne $state{'hash'}) { - die("Invalid passphrase\n"); - } - - return $pass; -} - -sub get_xdg_config_file { - my ($file) = @_; - my $env = $ENV{'XDG_CONFIG_HOME'}; - my $home = $ENV{'HOME'}; - - $file //= q{}; - $env //= "${home}/.config"; - - return "${env}/raps2/${file}"; -} - -sub get_xdg_data_file { - my ($file) = @_; - my $env = $ENV{'XDG_DATA_HOME'}; - my $home = $ENV{'HOME'}; - - $file //= q{}; - $env //= "${home}/.local/share"; - - return "${env}/raps2/${file}"; -} - -sub load_state_from { - my ($file) = @_; - - if (not -e $file) { - return; - } - - for my $line (slurp($file)) { - my ($key, $value) = split(qr{\s+}, $line); - - if (not ($key and $value)) { - next; - } - - $state{$key} = $value; - } - return; -} - -sub new_salt { - my $salt = q{}; - - for (1 .. 16) { - $salt .= chr(0x21 + int(rand(90))); - } - - return $salt; -} - -sub save_state_to { - my ($file) = @_; - my $raw = q{}; - - while (my ($key, $value) = each(%state)) { - $raw .= "${key} ${value}\n"; - } - - write_file($file, $raw); - return; -} - -sub setup_cipher { - my ($password) = @_; - - my $eksblowfish = Crypt::Eksblowfish->new( - $state{'cost'}, - $state{'salt'}, - $password, - ); - return Crypt::CBC->new(-cipher => $eksblowfish); -} - -sub to_clipboard { - my ($pw) = @_; - - open(my $clipboard, '|-', 'xclip -l 1'); - print $clipboard $pw; - close($clipboard); - return; -} - -sub read_input { - my %opts = @_; - my ($prefix, $invisible, $verify) - = @opts{'prefix', 'invisible', 'verify'}; - my $term = POSIX::Termios->new(); - my ($input1, $input2); - - if ($invisible) { - $term->getattr(0); - $term->setlflag($term->getlflag() & ~POSIX::ECHO); - $term->setattr(0, POSIX::TCSANOW); - } - - print "${prefix}: "; - $input1 = readline(STDIN); - - if ($invisible) { - print "\n"; - } - - if ($verify) { - print 'Verify: '; - $input2 = readline(STDIN); - - if ($invisible) { - print "\n"; - } - } - - if ($invisible) { - $term->setlflag($term->getlflag() | POSIX::ECHO); - $term->setattr(0, POSIX::TCSANOW); - } - - if ($verify and $input1 ne $input2) { - die("Lines do not match\n"); - } - - chomp $input1; - return $input1; -} - -create_dot_dirs(); +$raps2->sanity_check(); +$raps2->load_config(); given ($action) { - when ('add') { cmd_add(@args) } - when ('dump') { cmd_dump(@args) } - when ('get') { cmd_get(@args) } - when ('info') { cmd_info(@args) } - when ('list') { cmd_list(@args) } + when ('add') { $raps2->cmd_add(@args) } + when ('dump') { $raps2->cmd_dump(@args) } + when ('info') { $raps2->cmd_info(@args) } } __END__ -- cgit v1.2.3