summaryrefslogtreecommitdiff
path: root/lib/App/Raps2
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2011-05-20 14:54:15 +0200
committerDaniel Friesel <derf@finalrewind.org>2011-05-20 14:54:15 +0200
commit5b375768101d93054d42f9326f010d6f8019f541 (patch)
tree131be86ad1466890e7f884dbdbc0d9903fdc961f /lib/App/Raps2
parentcafd103a950682711fdc9e155d73da7f2fc59caa (diff)
Syntax cleanup
Diffstat (limited to 'lib/App/Raps2')
-rw-r--r--lib/App/Raps2/Password.pm227
-rw-r--r--lib/App/Raps2/UI.pm208
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).