From eb5fa3c9d404628bc7954188f286cb846aa0a371 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Apr 2015 11:30:36 +0300 Subject: [PATCH 1/6] Goup add to DB schema --- Database.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Database.pm b/Database.pm index 16336b2..e613d9d 100644 --- a/Database.pm +++ b/Database.pm @@ -138,7 +138,7 @@ sub create_base { print "Create database schema\n"; my $q_table = "create table passwords(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(32), username VARCHAR(32), - resource TEXT, password TEXT, comment TEXT)"; + resource TEXT, group VARCHAR(32), password TEXT, comment TEXT)"; $dbh->do($q_table); print "Encrypt database...\n"; From de8a7421e4ca54d6db07a5ccb5c0f1241d397c45 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Apr 2015 12:01:28 +0300 Subject: [PATCH 2/6] Schema creation fix --- Database.pm | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Database.pm b/Database.pm index e613d9d..2f7b35d 100644 --- a/Database.pm +++ b/Database.pm @@ -45,7 +45,7 @@ sub mdo { # Bad hack if ( $name eq 'all' ) { my $q - = 'select id, name, resource, username, comment from passwords'; + = 'select id, name, `group`, resource, username, comment from passwords'; my $sth = $dbh->prepare($q); my $rv = $sth->execute(); @@ -54,19 +54,21 @@ sub mdo { printf "%-11s %-11s %-11s %-11s %-11s\n", colored( "ID", 'white' ), colored( "NAME", 'magenta' ), + colored( "GROUP", 'bold magenta' ), colored( "RESOURCE", 'blue' ), colored( "USERNAME", 'green' ), colored( "COMMENT", 'yellow' ); - print "=================================\n"; - while ( my ( $id, $name, $resource, $username, $comment ) + print "=========================================\n"; + while ( my ( $id, $name, $group, $resource, $username, $comment ) = $sth->fetchrow_array() ) { if ( !defined($comment) ) { $comment = ''; } - printf "%-11s %-11s %-11s %-11s %-11s\n", + printf "%-11s %-11s %-11s %-11s %-11s %-11s\n", colored( $id, 'white' ), colored( $name, 'magenta' ), + colored( $group, 'bold magenta' ), colored( $resource, 'blue' ), colored( $username, 'green' ), colored( $comment, 'yellow' ); @@ -137,8 +139,15 @@ sub create_base { my $dbh = DBI->connect( "dbi:SQLite:dbname=$first_sqlite", "", "" ); print "Create database schema\n"; my $q_table - = "create table passwords(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(32), username VARCHAR(32), - resource TEXT, group VARCHAR(32), password TEXT, comment TEXT)"; + = "CREATE TABLE passwords( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + name VARCHAR(32) NOT NULL, + username VARCHAR(32) NOT NULL, + resource TEXT NOT NULL, + password VARCHAR(32) NOT NULL, + comment TEXT NOT NULL, + 'group' VARCHAR(32) NOT NULL + )"; $dbh->do($q_table); print "Encrypt database...\n"; From 0e92985b5e2bc356c4dbd691d4c7b3332d93f6f1 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Apr 2015 12:50:56 +0300 Subject: [PATCH 3/6] Groups support. Dirty hack --- Database.pm | 36 +++++++++++++++++++++++++++++++++++- Password.pm | 41 ++++++++++++++++++++++++++++------------- pm.pl | 15 +++++++++++---- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/Database.pm b/Database.pm index 2f7b35d..8e251a5 100644 --- a/Database.pm +++ b/Database.pm @@ -2,6 +2,7 @@ package Database; use DBI; use GPG; +use Term::ANSIColor; use Password; @@ -36,6 +37,7 @@ sub mdo { my $q = $query->{query}; my $name = $query->{name}; my $type = $query->{type}; + my $g = $query->{group}; my $dbh = Database->connect($db_file); @@ -50,7 +52,6 @@ sub mdo { my $sth = $dbh->prepare($q); my $rv = $sth->execute(); - use Term::ANSIColor; printf "%-11s %-11s %-11s %-11s %-11s\n", colored( "ID", 'white' ), colored( "NAME", 'magenta' ), @@ -81,6 +82,39 @@ sub mdo { exit 0; } + # Show group + if ($g) { + my $sth = $dbh->prepare($q); + my $rv = $sth->execute(); + + printf "%-11s %-11s %-11s %-11s %-11s\n", + colored( "ID", 'white' ), + colored( "NAME", 'magenta' ), + colored( "GROUP", 'bold magenta' ), + colored( "RESOURCE", 'blue' ), + colored( "USERNAME", 'green' ), + colored( "COMMENT", 'yellow' ); + print "=========================================\n"; + + while ( my ( $id, $name, $group, $resource, $username, $comment ) + = $sth->fetchrow_array() ) + { + printf "%-11s %-11s %-11s %-11s %-11s %-11s\n", + colored( $id, 'white' ), + colored( $name, 'magenta' ), + colored( $group, 'bold magenta' ), + colored( $resource, 'blue' ), + colored( $username, 'green' ), + colored( $comment, 'yellow' ); + } + + # Remove unencrypted file + my @rm_cmd = ( "rm", "-f", "$db_file" ); + system(@rm_cmd) == 0 + or die "Cannot remove unencrypted database! $!\n"; + exit 0; + } + my $sth = $dbh->prepare($q); $sth->execute(); diff --git a/Password.pm b/Password.pm index 3d80b42..6ecd69b 100644 --- a/Password.pm +++ b/Password.pm @@ -26,7 +26,7 @@ sub new { } sub show { - my ( $self, $name, $username ) = @_; + my ( $self, $name, $username, $g ) = @_; my $db_class = $self->{_db}; my $gpg = $self->{_gpg}; @@ -35,21 +35,34 @@ sub show { # Query my $query_string; - if ( defined($username) ) { + if ( defined($username) and !($g)) { $query_string = "select id, name, resource, password from passwords where name='$name' and username='$username'"; } + # Fasthack + elsif ( defined($g)) { + $query_string = "select id, name, `group`, resource, username, comment from passwords where `group`='$g'"; + } else { $query_string = "select id, name, resource, password from passwords where name='$name'"; } - my $mdo_q = { + my $mdo_q; + + $mdo_q = { file => $dec_db_file, query => $query_string, name => $name, type => 'select', }; + $mdo_q = { + file => $dec_db_file, + query => $query_string, + name => $name, + type => 'select', + group => $g, + } if $g; my $q_hash = $db_class->mdo($mdo_q); # Remove unencrypted file @@ -103,6 +116,7 @@ sub save { my $name = $store->{name}; my $resource = $store->{resource}; my $password = $store->{password}; + my $group = $store->{group}; # Comment check my $comment = ''; @@ -119,8 +133,8 @@ sub save { # Decrypt database my $dec_db_file = $gpg->decrypt_db(); my $q - = "insert into passwords(name, resource, password, username, comment) - values('$name', '$resource', '$password', '$username', '$comment')"; + = "insert into passwords(name, resource, password, username, comment, 'group') + values('$name', '$resource', '$password', '$username', '$comment', '$group')"; my $mdo_q = { file => $dec_db_file, name => $name, @@ -137,16 +151,17 @@ sub save { # Generate password sub generate { my $value; - - open my $rnd, "<", "/dev/random"; - read $rnd, $value, 32; - my $c = unpack ("H*", $value); - - my @chars = split(//,$c); - push @chars, $_ for ( '!', '@', '(', ')','A'..'Z' ); + + open my $rnd, "<", "/dev/random"; + read $rnd, $value, 32; + my $c = unpack( "H*", $value ); + close $rnd; + + my @chars = split( //, $c ); + push @chars, $_ for ( '!', '@', '(', ')', 'A' .. 'Z' ); my $string; - $string .= $chars[ rand @chars ] for 1 .. 16; + $string .= $chars[ rand @chars ] for 1 .. 16; return $string; } diff --git a/pm.pl b/pm.pl index de62e33..c9e2161 100755 --- a/pm.pl +++ b/pm.pl @@ -15,11 +15,11 @@ our $VERSION = '0.0.1-beta1'; my $usage = Usage->new(); sub init() { - my $opt_string = 'swn:l:p:rhvou:i:c:x:'; + my $opt_string = 'swn:l:p:rhvou:i:c:x:g:'; getopts("$opt_string") or $usage->show(); our ( $opt_s, $opt_w, $opt_n, $opt_r, $opt_l, $opt_p, $opt_h, - $opt_v, $opt_o, $opt_u, $opt_i, $opt_c, $opt_x, + $opt_v, $opt_o, $opt_u, $opt_i, $opt_c, $opt_x, $opt_g, ); print "Simple password manager writed in Perl.\nVersion: " @@ -62,6 +62,11 @@ if ( defined($opt_s) and defined($opt_n) and !defined($opt_o) ) { print "Cancel\n" if $ans ne "Yes"; } } +if ( defined($opt_s) and defined($opt_g) ) { + + $pass->show( $opt_n, '', $opt_g ); + +} elsif ( defined($opt_s) and defined($opt_n) and defined($opt_o) ) { my $get_h = $pass->show( $opt_n, $opt_u ); @@ -90,7 +95,7 @@ elsif ( defined($opt_w) and !defined($opt_p) ) { # Generate password and store it into DB - print "$opt_w, $opt_n, $opt_l, $opt_p\n"; + $opt_g = '' if !($opt_g); $opt_p = $pass->generate(); @@ -100,6 +105,7 @@ elsif ( defined($opt_w) password => $opt_p, username => $opt_u, comment => $opt_c, + group => $opt_g, }; $pass->save($store_h) == 0 or die "Oops! 105: pm.pl. $!\n"; @@ -112,7 +118,7 @@ elsif ( defined($opt_w) and defined($opt_p) ) { # Store new password into DB - print "$opt_w, $opt_n, $opt_l, $opt_p\n"; + $opt_g = '' if !($opt_g); my $store_h = { name => $opt_n, @@ -121,6 +127,7 @@ elsif ( defined($opt_w) gen => 0, username => $opt_u, comment => $opt_c, + group => $opt_g, }; $pass->save($store_h) == 0 or die "Oops! 122: pm.pl. $!\n"; From d9ce921d4131248aa88ab21f1d96d7a813c26967 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Apr 2015 12:52:29 +0300 Subject: [PATCH 4/6] === --- Database.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Database.pm b/Database.pm index 8e251a5..0951f61 100644 --- a/Database.pm +++ b/Database.pm @@ -94,7 +94,7 @@ sub mdo { colored( "RESOURCE", 'blue' ), colored( "USERNAME", 'green' ), colored( "COMMENT", 'yellow' ); - print "=========================================\n"; + print "===============================\n"; while ( my ( $id, $name, $group, $resource, $username, $comment ) = $sth->fetchrow_array() ) From b9a9ecf3ef19b5ee3409225205693eadddf7b246 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Apr 2015 13:43:40 +0300 Subject: [PATCH 5/6] 0.0.2-beta --- pm.pl | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pm.pl b/pm.pl index c9e2161..84ac2e7 100755 --- a/pm.pl +++ b/pm.pl @@ -10,7 +10,7 @@ use Usage; # Debug use Data::Dumper; -our $VERSION = '0.0.1-beta1'; +our $VERSION = '0.0.1'; my $usage = Usage->new(); @@ -49,23 +49,25 @@ if ( defined($opt_s) and defined($opt_n) and !defined($opt_o) ) { if ( defined( $ENV{'DISPLAY'} ) ) { $copy->copy($get_pass); - print colored("Password copied to xclipboard.", 'green'); + print colored( "Password copied to xclipboard.", 'green' ); print "\nURI is "; - print colored($get_h->{resource} . "\n", 'bold blue'); + print colored( $get_h->{resource} . "\n", 'bold blue' ); } else { - print colored("Warning! Password will show to terminal!", 'red'); + print colored( "Warning! Password will show to terminal!", 'red' ); print " Yes/No: "; my $ans = ; chomp($ans); print "$get_pass\n" if $ans eq "Yes"; print "Cancel\n" if $ans ne "Yes"; } + + exit 0; } if ( defined($opt_s) and defined($opt_g) ) { $pass->show( $opt_n, '', $opt_g ); - + } elsif ( defined($opt_s) and defined($opt_n) and defined($opt_o) ) { @@ -76,9 +78,9 @@ elsif ( defined($opt_s) and defined($opt_n) and defined($opt_o) ) { my @open_cmd = ( 'xdg-open', $get_h->{resource} ); system(@open_cmd) == 0 or die "Cannot open URI: $!\n"; - print colored("Password copied to clipboard.\n", 'bold green'); + print colored( "Password copied to clipboard.\n", 'bold green' ); print "Trying to open "; - print colored($get_h->{resource} . "\n", 'bold blue'); + print colored( $get_h->{resource} . "\n", 'bold blue' ); } # Remove string from db @@ -87,7 +89,7 @@ elsif ( defined($opt_r) and defined($opt_i) ) { my $store_h = { id => $opt_i, }; $pass->remove($store_h) == 0 or die "Oops! 111: pm.pl. $!\n"; - print colored("Password was removed!\n", 'bold red'); + print colored( "Password was removed!\n", 'bold red' ); } elsif ( defined($opt_w) and defined($opt_n) @@ -110,7 +112,7 @@ elsif ( defined($opt_w) $pass->save($store_h) == 0 or die "Oops! 105: pm.pl. $!\n"; $copy->copy($opt_p); - print colored("Password was stored into DB!\n", 'green'); + print colored( "Password was stored into DB!\n", 'green' ); } elsif ( defined($opt_w) and defined($opt_n) @@ -131,12 +133,13 @@ elsif ( defined($opt_w) }; $pass->save($store_h) == 0 or die "Oops! 122: pm.pl. $!\n"; - print colored("Password was stored into DB!\n", 'green'); + print colored( "Password was stored into DB!\n", 'green' ); } + # Export elsif ( defined($opt_x) ) { $pass->export($opt_x); - print colored("Dabase stored in $opt_x\n", 'green'); + print colored( "Dabase stored in $opt_x\n", 'green' ); } else { $usage->show(); From d3e5db83056c6446fe3850a2a81c23feafe2b544 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 10 Jul 2015 12:55:59 +0300 Subject: [PATCH 6/6] More entropy --- Password.pm | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/Password.pm b/Password.pm index 6ecd69b..645d290 100644 --- a/Password.pm +++ b/Password.pm @@ -7,6 +7,9 @@ use utf8; use Database; use GPG; +use Digest::MD5; +use MIME::Base64; + # Debug use Data::Dumper; @@ -151,17 +154,40 @@ sub save { # Generate password sub generate { my $value; + + # Defaults + my $length = 16; - open my $rnd, "<", "/dev/random"; - read $rnd, $value, 32; - my $c = unpack( "H*", $value ); - close $rnd; + my $digest; + for (1..32) { + open my $rnd, "<", "/dev/urandom"; + read $rnd, $value, 1000; + my $c = unpack( "H*", $value ); + close $rnd; - my @chars = split( //, $c ); - push @chars, $_ for ( '!', '@', '(', ')', 'A' .. 'Z' ); + # MORE ENTROPY + my $ctx = Digest::MD5->new(); + $ctx->add($c); + + # MORE + my $encoded = encode_base64( $ctx->hexdigest() ); + $encoded =~ s/=//g; + $encoded =~ s/\n//g; + + $digest .= $encoded; + } + + my @chars = split( //, $digest ); + + my @r_special = ( '!', '@', '(', ')', '#', '$', '%', '^', '&' ); + for (1..10) { + foreach my $special (@r_special) { + $chars[ rand(@chars) ] = $special ]; + } + } my $string; - $string .= $chars[ rand @chars ] for 1 .. 16; + $string .= $chars[ rand @chars ] for 1 .. $length; return $string; }