diff --git a/Database.pm b/Database.pm index 16336b2..0951f61 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); @@ -45,28 +47,62 @@ 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(); - use Term::ANSIColor; 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' ); + } + + # Remove unencrypted file + my @rm_cmd = ( "rm", "-f", "$db_file" ); + system(@rm_cmd) == 0 + or die "Cannot remove unencrypted database! $!\n"; + 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' ); @@ -137,8 +173,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, 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"; diff --git a/Password.pm b/Password.pm index 3d80b42..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; @@ -26,7 +29,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 +38,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 +119,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 +136,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, @@ -138,15 +155,39 @@ sub save { sub generate { my $value; - open my $rnd, "<", "/dev/random"; - read $rnd, $value, 32; - my $c = unpack ("H*", $value); + # Defaults + my $length = 16; + + my $digest; + for (1..32) { + open my $rnd, "<", "/dev/urandom"; + read $rnd, $value, 1000; + my $c = unpack( "H*", $value ); + close $rnd; + + # 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 @chars = split(//,$c); - push @chars, $_ for ( '!', '@', '(', ')','A'..'Z' ); + 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; } diff --git a/pm.pl b/pm.pl index de62e33..84ac2e7 100755 --- a/pm.pl +++ b/pm.pl @@ -10,16 +10,16 @@ use Usage; # Debug use Data::Dumper; -our $VERSION = '0.0.1-beta1'; +our $VERSION = '0.0.1'; 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: " @@ -49,18 +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) ) { @@ -71,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 @@ -82,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) @@ -90,7 +97,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,11 +107,12 @@ 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"; $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) @@ -112,7 +120,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,15 +129,17 @@ 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"; - 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();