diff options
author | Daniel Friesel <derf@finalrewind.org> | 2011-05-20 14:54:15 +0200 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2011-05-20 14:54:15 +0200 |
commit | 5b375768101d93054d42f9326f010d6f8019f541 (patch) | |
tree | 131be86ad1466890e7f884dbdbc0d9903fdc961f /lib/App/Raps2 | |
parent | cafd103a950682711fdc9e155d73da7f2fc59caa (diff) |
Syntax cleanup
Diffstat (limited to 'lib/App/Raps2')
-rw-r--r-- | lib/App/Raps2/Password.pm | 227 | ||||
-rw-r--r-- | lib/App/Raps2/UI.pm | 208 |
2 files changed, 221 insertions, 214 deletions
diff --git a/lib/App/Raps2/Password.pm b/lib/App/Raps2/Password.pm index 1e33f58..1a3ab63 100644 --- a/lib/App/Raps2/Password.pm +++ b/lib/App/Raps2/Password.pm @@ -11,6 +11,103 @@ use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 de_base64); our $VERSION = '0.3'; +sub new { + my ( $obj, %conf ) = @_; + + $conf{cost} //= 12; + + if ( not defined $conf{salt} ) { + $conf{salt} = create_salt(); + } + + if ( length( $conf{salt} ) != 16 ) { + confess('incorrect salt length'); + } + + if ( not( defined $conf{passphrase} and length $conf{passphrase} ) ) { + confess('no passphrase given'); + } + + my $ref = \%conf; + + return bless( $ref, $obj ); +} + +sub create_salt { + my ($self) = @_; + my $salt = q{}; + + for ( 1 .. 16 ) { + $salt .= chr( 0x21 + int( rand(90) ) ); + } + + return $salt; +} + +sub salt { + my ( $self, $salt ) = @_; + + if ( defined $salt ) { + if ( length($salt) != 16 ) { + confess('incorrect salt length'); + } + + $self->{salt} = $salt; + } + + return $self->{salt}; +} + +sub encrypt { + my ( $self, $in ) = @_; + + my $eksblowfish = Crypt::Eksblowfish->new( $self->{cost}, $self->{salt}, + $self->{passphrase}, ); + my $cbc = Crypt::CBC->new( -cipher => $eksblowfish ); + + return $cbc->encrypt_hex($in); +} + +sub decrypt { + my ( $self, $in ) = @_; + + my $eksblowfish = Crypt::Eksblowfish->new( $self->{cost}, $self->{salt}, + $self->{passphrase}, ); + my $cbc = Crypt::CBC->new( -cipher => $eksblowfish ); + + return $cbc->decrypt_hex($in); +} + +sub bcrypt { + my ($self) = @_; + + return en_base64( + bcrypt_hash( + { + key_nul => 1, + cost => $self->{cost}, + salt => $self->{salt}, + }, + $self->{passphrase}, + ) + ); +} + +sub verify { + my ( $self, $testhash ) = @_; + + my $myhash = $self->bcrypt(); + + if ( $testhash eq $myhash ) { + return 1; + } + confess('Passwords did not match'); +} + +1; + +__END__ + =head1 NAME App::Raps2::Password - Password class for App::Raps2 @@ -23,7 +120,7 @@ App::Raps2::Password - Password class for App::Raps2 passphrase => 'secret', ); - my $oneway_hash = $raps2->crypt(); + my $oneway_hash = $raps2->bcrypt(); $raps2->verify($oneway_hash); my $twoway_hash = $raps2->encrypt('data'); @@ -34,6 +131,10 @@ App::Raps2::Password - Password class for App::Raps2 This manual documents B<App::Raps2::Password> version 0.3 +=head1 DESCRIPTION + +App::Raps2::Pasword is a wrapper around Crypt::Eksblowfish. + =head1 METHODS =over @@ -60,153 +161,47 @@ generates its own. =back -=cut - -sub new { - my ($obj, %conf) = @_; - - $conf{cost} //= 12; - - if (not defined $conf{salt}) { - $conf{salt} = create_salt(); - } - - if (length($conf{salt}) != 16) { - confess('incorrect salt length'); - } - - if (not (defined $conf{passphrase} and length $conf{passphrase})) { - confess('no passphrase given'); - } - - my $ref = \%conf; - - return bless($ref, $obj); -} - =item $pass->create_salt() Returns a new 16-byte salt. Contains only printable characters. -=cut - -sub create_salt { - my ($self) = @_; - my $salt = q{}; - - for (1 .. 16) { - $salt .= chr(0x21 + int(rand(90))); - } - - return $salt; -} - =item $pass->salt([I<salt>]) Returns the currently used salt and optionally changes it to I<salt>. -=cut - -sub salt { - my ($self, $salt) = @_; - - if (defined $salt) { - if (length($salt) != 16) { - confess('incorrect salt length'); - } - - $self->{salt} = $salt; - } - - return $self->{salt}; -} - =item $pass->encrypt(I<data>) Encrypts I<data> with the passphrase saved in the object, returns the corresponding hexadecimal hash (as string). -=cut - -sub encrypt { - my ($self, $in) = @_; - - my $eksblowfish = Crypt::Eksblowfish->new( - $self->{cost}, - $self->{salt}, - $self->{passphrase}, - ); - my $cbc = Crypt::CBC->new(-cipher => $eksblowfish); - - return $cbc->encrypt_hex($in); -} - =item $pass->decrypt(I<hexstr>) Decrypts I<hexstr> (as created by B<encrypt>), returns its original content. -=cut - -sub decrypt { - my ($self, $in) = @_; - - my $eksblowfish = Crypt::Eksblowfish->new( - $self->{cost}, - $self->{salt}, - $self->{passphrase}, - ); - my $cbc = Crypt::CBC->new(-cipher => $eksblowfish); - - return $cbc->decrypt_hex($in); -} - -=item $pass->crypt() +=item $pass->bcrypt() Return a base64 bcrypt hash of the password, salted with the salt. -=cut - -sub crypt { - my ($self) = @_; - - return en_base64( - bcrypt_hash({ - key_nul => 1, - cost => $self->{cost}, - salt => $self->{salt}, - }, - $self->{passphrase}, - )); -} - =item $pass->verify(I<hash>) Verify a hash as returned by B<crypt>. Returns true if it matches, dies if it doesn't. -=cut - -sub verify { - my ($self, $testhash) = @_; - - my $myhash = $self->crypt(); +=back - if ($testhash eq $myhash) { - return 1; - } - confess('Passwords did not match'); -} +=head1 DIAGNOSTICS -1; +When anything goes wrong, App::Raps2::Password will use Carp(3pm)'s B<confess> +method to die with a backtrace. -__END__ +=head1 DEPENDENCIES -=back +Crypt::CBC(3pm), Crypt::Eksblowfish(3pm). -=head1 DEPENDENCIES +=head1 BUGS AND LIMITATIONS -B<Crypt::CBC>, B<Crypt::Eksblowfish>. +Unknown. =head1 SEE ALSO diff --git a/lib/App/Raps2/UI.pm b/lib/App/Raps2/UI.pm index 4d7f3d0..b588222 100644 --- a/lib/App/Raps2/UI.pm +++ b/lib/App/Raps2/UI.pm @@ -10,113 +10,61 @@ use Term::ReadLine; our $VERSION = '0.3'; -=head1 NAME - -App::Raps2::UI - App::Raps2 User Interface - -=head1 SYNOPSIS - - my $ui = App::Raps2::UI->new(); - - my $input = $ui->read_line('Say something'); - - my $password = $ui->read_pw('New password', 1); - - $ui->to_clipboard('stuff!'); - -=head1 VERSION - -This manual documents B<App::Raps2::UI> version 0.3 - -=head1 METHODS - -=over - -=item $ui = App::Raps2::UI->new() - -Returns a new App::Raps2::UI object. - -=cut - sub new { my ($obj) = @_; - my $ref = {}; - $ref->{term_readline} = Term::ReadLine->new('App::Raps2'); - return bless($ref, $obj); -} -=item $ui->list(I<\@item1>, I<\@item2>, I<\@item3>) + my $ref = {}; -Print the list items neatly formatted to stdout. Each I<item> looks like B<[> -I<key>, I<value> B<]>. When B<list> is called for the first time, it will -print the keys as well as the values. + $ref->{term_readline} = Term::ReadLine->new('App::Raps2'); -=cut + return bless( $ref, $obj ); +} sub list { - my ($self, @list) = @_; + my ( $self, @list ) = @_; + my $format = "%-20s %-20s %s\n"; - if (not $self->{list}->{header}) { - printf($format, map { $_->[0] } @list); + if ( not $self->{list}->{header} ) { + printf( $format, map { $_->[0] } @list ); $self->{list}->{header} = 1; } - printf($format, map { $_->[1] // q{} } @list); -} - -=item $ui->read_line(I<$question>, [I<$prefill>]) - -Print "I<question>: " to stdout and wait for the user to input text followed -by a newline. I<prefill> sets the default content of the answer field. - -Returns the user's reply, excluding the newline. + printf( $format, map { $_->[1] // q{} } @list ); -=cut + return; +} sub read_line { - my ($self, $str, $pre) = @_; + my ( $self, $str, $pre ) = @_; - my $input = $self->{term_readline}->readline("${str}: ", $pre); + my $input = $self->{term_readline}->readline( "${str}: ", $pre ); return $input; } -=item $ui->read_multiline(I<$message>) - -Like B<read_line>, but repeats I<message> each time the user hits return. -Input is terminated by EOF (Ctrl+D). Returns a string concatenation of all -lines (including newlines). - -=cut - sub read_multiline { - my ($self, $str) = @_; + my ( $self, $str ) = @_; + my $in; say "${str} (^D to quit)"; - while (my $line = $self->read_line('multiline')) { + while ( my $line = $self->read_line('multiline') ) { $in .= "${line}\n"; } + return $in; } -=item $ui->read_pw(I<$message>, I<$verify>) - -Prompt the user for a password. I<message> is displayed, the user's input is -noch echoed. If I<verify> is set, the user has to enter the same input twice, -otherwise B<read_pw> dies. Returns the input. - -=cut - sub read_pw { - my ($self, $str, $verify) = @_; - my ($in1, $in2); + my ( $self, $str, $verify ) = @_; + my ( $in1, $in2 ); my $term = POSIX::Termios->new(); + $term->getattr(0); - $term->setlflag($term->getlflag() & ~POSIX::ECHO); - $term->setattr(0, POSIX::TCSANOW); + $term->setlflag( $term->getlflag() & ~POSIX::ECHO ); + $term->setattr( 0, POSIX::TCSANOW ); print "${str}: "; $in1 = readline(STDIN); @@ -128,49 +76,39 @@ sub read_pw { print "\n"; } - $term->setlflag($term->getlflag() | POSIX::ECHO); - $term->setattr(0, POSIX::TCSANOW); + $term->setlflag( $term->getlflag() | POSIX::ECHO ); + $term->setattr( 0, POSIX::TCSANOW ); - if ($verify and $in1 ne $in2) { + if ( $verify and $in1 ne $in2 ) { confess('Input lines did not match'); } chomp $in1; + return $in1; } -=item $ui->to_clipboard(I<$string>) +sub to_clipboard { + my ( $self, $str ) = @_; -Place I<string> in the primary X Clipboard. + open( my $clipboard, q{|-}, 'xclip -l 1' ) + or confess("Failed to execute xclip -l 1: $!"); -=cut + print $clipboard $str; -sub to_clipboard { - my ($self, $str) = @_; + close($clipboard) + or confess("Failed to close pipe to xclip: $!"); - open(my $clipboard, '|-', 'xclip -l 1'); - print $clipboard $str; - close($clipboard); return; } -=item $ui->output(I<\@pair>, I<...>) - -I<pair> consinsts of B<[> I<key>, I<value> B<]>. For each I<pair>, prints -" key : value" to stdout. - -=cut - sub output { - my ($self, @out) = @_; + my ( $self, @out ) = @_; for my $pair (@out) { - printf( - "%-8s : %s\n", - $pair->[0], - $pair->[1] // q{}, - ); + printf( "%-8s : %s\n", $pair->[0], $pair->[1] // q{}, ); } + return; } @@ -178,12 +116,86 @@ sub output { __END__ +=head1 NAME + +App::Raps2::UI - App::Raps2 User Interface + +=head1 SYNOPSIS + + my $ui = App::Raps2::UI->new(); + + my $input = $ui->read_line('Say something'); + + my $password = $ui->read_pw('New password', 1); + + $ui->to_clipboard('stuff!'); + +=head1 VERSION + +This manual documents B<App::Raps2::UI> version 0.3 + +=head1 DESCRIPTION + +App::Raps2::UI is used by App::Raps2 to interface with the user, i.e. do input +and output on the terminal. + +=head1 METHODS + +=over + +=item $ui = App::Raps2::UI->new() + +Returns a new App::Raps2::UI object. + +=item $ui->list(I<\@item1>, I<\@item2>, I<\@item3>) + +Print the list items neatly formatted to stdout. Each I<item> looks like B<[> +I<key>, I<value> B<]>. When B<list> is called for the first time, it will +print the keys as well as the values. + +=item $ui->read_line(I<$question>, [I<$prefill>]) + +Print "I<question>: " to stdout and wait for the user to input text followed +by a newline. I<prefill> sets the default content of the answer field. + +Returns the user's reply, excluding the newline. + +=item $ui->read_multiline(I<$message>) + +Like B<read_line>, but repeats I<message> each time the user hits return. +Input is terminated by EOF (Ctrl+D). Returns a string concatenation of all +lines (including newlines). + +=item $ui->read_pw(I<$message>, I<$verify>) + +Prompt the user for a password. I<message> is displayed, the user's input is +noch echoed. If I<verify> is set, the user has to enter the same input twice, +otherwise B<read_pw> dies. Returns the input. + +=item $ui->to_clipboard(I<$string>) + +Place I<string> in the primary X Clipboard. + +=item $ui->output(I<\@pair>, I<...>) + +I<pair> consinsts of B<[> I<key>, I<value> B<]>. For each I<pair>, prints +" key : value" to stdout. + =back +=head1 DIAGNOSTICS + +When App::Raps2::UI encounters an error, it uses Carp(3pm)'s B<confess> +function to die with a backtrace. + =head1 DEPENDENCIES This module requires B<Term::ReadLine> and the B<xclip> executable. +=head1 BUGS AND LIMITATIONS + +Unknown. + =head1 SEE ALSO App::Raps2(3pm). |