enhanced unittests, added pod for addrecord and newrecord, using ->new() everywhere, new parameter "create"

This commit is contained in:
git@daemon.de
2015-02-16 11:41:35 +01:00
parent f8308c72c4
commit 1672943fcc
7 changed files with 208 additions and 156 deletions

View File

@@ -1,6 +1,21 @@
NEXT: NEXT:
added license to META added license to META
open tmpfiles with O_EXLOCK disabled (cpantesters)
added new parameter 'create', enabled by default,
which creates a new vault if enabled and dies otherwise.
enhanced unit tests to report if read/write of files fails.
added unit test to create a new vault
added POD for newrecord() and addrecord(), previously
missing.
replaced "new $perl::$object" with $perl::$object->new()
everywhere.
1.16 1.16
re-licensed from artistic1 to artistic2 in order to be re-licensed from artistic1 to artistic2 in order to be
compatible to fedora packaging. no code changes otherwise compatible to fedora packaging. no code changes otherwise

View File

@@ -29,7 +29,7 @@ use Data::Dumper;
use Exporter (); use Exporter ();
use vars qw(@ISA @EXPORT); use vars qw(@ISA @EXPORT);
$Crypt::PWSafe3::VERSION = '1.16'; $Crypt::PWSafe3::VERSION = '1.17';
use Crypt::PWSafe3::Field; use Crypt::PWSafe3::Field;
use Crypt::PWSafe3::HeaderField; use Crypt::PWSafe3::HeaderField;
@@ -92,7 +92,7 @@ sub new {
# new vault object # new vault object
my($this, %param) = @_; my($this, %param) = @_;
my $class = ref($this) || $this; my $class = ref($this) || $this;
my $self = \%param; # file, password, whoami, program my $self = \%param; # file, password, whoami, program, create
bless($self, $class); bless($self, $class);
# sanity checks # sanity checks
@@ -108,13 +108,22 @@ sub new {
croak 'Parameter password is required'; croak 'Parameter password is required';
} }
if (! exists $self->{create}) {
$self->{create} = 1;
}
if (! exists $self->{file}) { if (! exists $self->{file}) {
$self->{file} = ''; $self->{file} = '';
$self->create(); $self->create();
} }
else { else {
if (! -s $self->{file}) { if (! -s $self->{file} || ! -r $self->{file}) {
$self->create(); if ($self->{create}) {
$self->create();
}
else {
croak "PWSafe3 file $self->{file} does not exist or is not readable";
}
} }
else { else {
$self->read(); $self->read();
@@ -133,7 +142,7 @@ sub stretchpw {
# algorithm is described here: # algorithm is described here:
# [KEYSTRETCH Section 4.1] http://www.schneier.com/paper-low-entropy.pdf # [KEYSTRETCH Section 4.1] http://www.schneier.com/paper-low-entropy.pdf
my ($this, $passwd) = @_; my ($this, $passwd) = @_;
my $sha = new Digest::SHA('SHA-256'); my $sha = Digest::SHA->new('SHA-256');
$sha->reset(); $sha->reset();
$sha->add( ( $passwd, $this->salt) ); $sha->add( ( $passwd, $this->salt) );
my $stretched = $sha->digest(); my $stretched = $sha->digest();
@@ -160,7 +169,7 @@ sub create {
$this->strechedpw($this->stretchpw($this->password())); $this->strechedpw($this->stretchpw($this->password()));
# generate hash of the streched pw # generate hash of the streched pw
my $sha = new Digest::SHA('SHA-256'); my $sha = Digest::SHA->new('SHA-256');
$sha->reset(); $sha->reset();
$sha->add( ( $this->strechedpw() ) ); $sha->add( ( $this->strechedpw() ) );
$this->shaps( $sha->digest() ); $this->shaps( $sha->digest() );
@@ -183,17 +192,17 @@ sub create {
$this->iv( $this->random(16) ); $this->iv( $this->random(16) );
# create hmac'er and cipher for actual encryption # create hmac'er and cipher for actual encryption
$this->{hmacer} = new Digest::HMAC($this->keyl, "Crypt::PWSafe3::SHA256"); $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
$this->{cipher} = new Crypt::CBC( $this->{cipher} = Crypt::CBC->new(
-key => $this->keyk, -key => $this->keyk,
-iv => $this->iv, -iv => $this->iv,
-cipher => 'Twofish', -cipher => 'Twofish',
-header => 'none', -header => 'none',
-padding => 'null', -padding => 'null',
-literal_key => 1, -literal_key => 1,
-keysize => 32, -keysize => 32,
-blocksize => 16 -blocksize => 16
); );
# empty for now # empty for now
$this->hmac( $this->{hmacer}->digest() ); $this->hmac( $this->{hmacer}->digest() );
@@ -204,7 +213,7 @@ sub read {
# read and decrypt an existing vault file # read and decrypt an existing vault file
my($this) = @_; my($this) = @_;
my $fd = new FileHandle($this->file, 'r'); my $fd = FileHandle->new($this->file, 'r');
$fd->binmode(); $fd->binmode();
$this->{fd} = $fd; $this->{fd} = $fd;
@@ -218,13 +227,12 @@ sub read {
$this->strechedpw($this->stretchpw($this->password())); $this->strechedpw($this->stretchpw($this->password()));
my $sha = new Digest::SHA(256); my $sha = Digest::SHA->new(256);
$sha->reset(); $sha->reset();
$sha->add( ( $this->strechedpw() ) ); $sha->add( ( $this->strechedpw() ) );
$this->shaps( $sha->digest() ); $this->shaps( $sha->digest() );
my $fileshaps = $this->readbytes(32); my $fileshaps = $this->readbytes(32);
#print "sha1: <" . unpack('H*', $fileshaps) . ">\nsha2: <" . unpack('H*', $this->shaps) . ">\n";
if ($fileshaps ne $this->shaps) { if ($fileshaps ne $this->shaps) {
croak "Wrong password!"; croak "Wrong password!";
} }
@@ -241,14 +249,11 @@ sub read {
$this->keyk($crypt->decrypt($this->b1) . $crypt->decrypt($this->b2)); $this->keyk($crypt->decrypt($this->b1) . $crypt->decrypt($this->b2));
$this->keyl($crypt->decrypt($this->b3) . $crypt->decrypt($this->b4)); $this->keyl($crypt->decrypt($this->b3) . $crypt->decrypt($this->b4));
#print "keyk:<" . unpack('H*', $this->keyk) . ">\n";
$this->iv( $this->readbytes(16) ); $this->iv( $this->readbytes(16) );
# create hmac'er and cipher for actual encryption # create hmac'er and cipher for actual encryption
$this->{hmacer} = new Digest::HMAC($this->keyl, "Crypt::PWSafe3::SHA256"); $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
#print "keyk len: " . length($this->keyk) . "\n"; $this->{cipher} = Crypt::CBC->new(
$this->{cipher} = new Crypt::CBC(
-key => $this->keyk, -key => $this->keyk,
-iv => $this->iv, -iv => $this->iv,
-cipher => 'Twofish', -cipher => 'Twofish',
@@ -274,7 +279,7 @@ sub read {
} }
# read db records # read db records
my $record = new Crypt::PWSafe3::Record(); my $record = Crypt::PWSafe3::Record->new();
$this->{record} = {}; $this->{record} = {};
while (1) { while (1) {
my $field = $this->readfield(); my $field = $this->readfield();
@@ -283,8 +288,7 @@ sub read {
} }
if ($field->type == 0xff) { if ($field->type == 0xff) {
$this->addrecord($record); $this->addrecord($record);
#print "--- record added (uuid:" . $record->uuid . ")\n"; $record = Crypt::PWSafe3::Record->new();
$record = new Crypt::PWSafe3::Record();
} }
else { else {
$record->addfield($field); $record->addfield($field);
@@ -338,14 +342,14 @@ sub save {
return; return;
} }
my $lastsave = new Crypt::PWSafe3::HeaderField(type => 0x04, value => time); my $lastsave = Crypt::PWSafe3::HeaderField->new(type => 0x04, value => time);
my $whatsaved = new Crypt::PWSafe3::HeaderField(type => 0x06, value => $this->{program}); my $whatsaved = Crypt::PWSafe3::HeaderField->new(type => 0x06, value => $this->{program});
my $whosaved = new Crypt::PWSafe3::HeaderField(type => 0x05, value => $this->{whoami}); my $whosaved = Crypt::PWSafe3::HeaderField->new(type => 0x05, value => $this->{whoami});
$this->addheader($lastsave); $this->addheader($lastsave);
$this->addheader($whatsaved); $this->addheader($whatsaved);
$this->addheader($whosaved); $this->addheader($whosaved);
my $fd = File::Temp->new(TEMPLATE => '.vaultXXXXXXXX', TMPDIR => 1) or croak "Could not open tmpfile: $!\n"; my $fd = File::Temp->new(TEMPLATE => '.vaultXXXXXXXX', TMPDIR => 1, EXLOCK => 0) or croak "Could not open tmpfile: $!\n";
my $tmpfile = "$fd"; my $tmpfile = "$fd";
$this->{fd} = $fd; $this->{fd} = $fd;
@@ -357,7 +361,7 @@ sub save {
$this->strechedpw($this->stretchpw($passwd)); $this->strechedpw($this->stretchpw($passwd));
# line 472 # line 472
my $sha = new Digest::SHA(256); my $sha = Digest::SHA->new(256);
$sha->reset(); $sha->reset();
$sha->add( ( $this->strechedpw() ) ); $sha->add( ( $this->strechedpw() ) );
$this->shaps( $sha->digest() ); $this->shaps( $sha->digest() );
@@ -377,8 +381,8 @@ sub save {
$this->writebytes($this->iv); $this->writebytes($this->iv);
$this->{hmacer} = new Digest::HMAC($this->keyl, "Crypt::PWSafe3::SHA256"); $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
$this->{cipher} = new Crypt::CBC( $this->{cipher} = Crypt::CBC->new(
-key => $this->keyk, -key => $this->keyk,
-iv => $this->iv, -iv => $this->iv,
-cipher => 'Twofish', -cipher => 'Twofish',
@@ -389,7 +393,7 @@ sub save {
-blocksize => 16 -blocksize => 16
); );
my $eof = new Crypt::PWSafe3::HeaderField(type => 0xff, value => ''); my $eof = Crypt::PWSafe3::HeaderField->new(type => 0xff, value => '');
foreach my $type (keys %{$this->{header}}) { foreach my $type (keys %{$this->{header}}) {
$this->writefield($this->{header}->{$type}); $this->writefield($this->{header}->{$type});
@@ -398,7 +402,7 @@ sub save {
$this->writefield($eof); $this->writefield($eof);
$this->hmacer($eof->{raw}); $this->hmacer($eof->{raw});
$eof = new Crypt::PWSafe3::Field(type => 0xff, value => ''); $eof = Crypt::PWSafe3::Field->new(type => 0xff, value => '');
foreach my $uuid (keys %{$this->{record}}) { foreach my $uuid (keys %{$this->{record}}) {
my $record = $this->{record}->{$uuid}; my $record = $this->{record}->{$uuid};
@@ -410,7 +414,7 @@ sub save {
$this->hmacer($eof->{raw}); $this->hmacer($eof->{raw});
} }
$this->writefield(new Crypt::PWSafe3::Field(type => 'none', raw => 0)); $this->writefield(Crypt::PWSafe3::Field->new(type => 'none', raw => 0));
$this->hmac( $this->{hmacer}->digest() ); $this->hmac( $this->{hmacer}->digest() );
$this->writebytes($this->hmac); $this->writebytes($this->hmac);
@@ -419,7 +423,7 @@ sub save {
# now try to read it in again to check if it # now try to read it in again to check if it
# is valid what we created # is valid what we created
eval { eval {
my $vault = new Crypt::PWSafe3(file => $tmpfile, password => $passwd); my $vault = Crypt::PWSafe3->new(file => $tmpfile, create => 0, password => $passwd);
}; };
if ($@) { if ($@) {
unlink $tmpfile; unlink $tmpfile;
@@ -436,8 +440,6 @@ sub writefield {
# write a field to vault file # write a field to vault file
my($this, $field) = @_; my($this, $field) = @_;
#print "write field " . $field->name . "\n";
if ($field->type eq 'none') { if ($field->type eq 'none') {
$this->writebytes("PWS3-EOFPWS3-EOF"); $this->writebytes("PWS3-EOFPWS3-EOF");
return; return;
@@ -459,19 +461,15 @@ sub writefield {
if (length($data) > 16) { if (length($data) > 16) {
my $crypt; my $crypt;
while (1) { while (1) {
#print "processing part\n";
my $part = substr($data, 0, 16); my $part = substr($data, 0, 16);
$crypt .= $this->encrypt($part); $crypt .= $this->encrypt($part);
if (length($data) <= 16) { if (length($data) <= 16) {
#print " this was the last one\n";
last; last;
} }
else { else {
#print " getting next\n";
$data = substr($data, 16); $data = substr($data, 16);
} }
} }
#print " len: " . length($crypt) . "\n";
$this->writebytes($crypt); $this->writebytes($crypt);
} }
else { else {
@@ -525,7 +523,6 @@ sub modifyrecord {
sub deleterecord { sub deleterecord {
# #
# delete a record identified by the given uuid, if present # delete a record identified by the given uuid, if present
#
# returns 1 if record was actually removed, 0 if it was not present # returns 1 if record was actually removed, 0 if it was not present
my($this, $uuid) = @_; my($this, $uuid) = @_;
@@ -546,14 +543,14 @@ sub markmodified {
# #
# mark the vault as modified by setting the appropriate header fields # mark the vault as modified by setting the appropriate header fields
my($this) = @_; my($this) = @_;
my $lastmod = new Crypt::PWSafe3::HeaderField( my $lastmod = Crypt::PWSafe3::HeaderField->new(
name => "lastsavetime", name => "lastsavetime",
value => time value => time
);
my $who = new Crypt::PWSafe3::HeaderField(
name => "wholastsaved",
value => $this->{whoami}
); );
my $who = Crypt::PWSafe3::HeaderField->new(
name => "wholastsaved",
value => $this->{whoami}
);
$this->addheader($lastmod); $this->addheader($lastmod);
$this->addheader($who); $this->addheader($who);
$this->{modified} = 1; $this->{modified} = 1;
@@ -563,7 +560,7 @@ sub newrecord {
# #
# add a new record to an existing vault # add a new record to an existing vault
my($this, %fields) = @_; my($this, %fields) = @_;
my $record = new Crypt::PWSafe3::Record(); my $record = Crypt::PWSafe3::Record->new();
foreach my $field (keys %fields) { foreach my $field (keys %fields) {
$record->modifyfield($field, $fields{$field}); $record->modifyfield($field, $fields{$field});
} }
@@ -599,18 +596,12 @@ sub readfield {
return 0; return 0;
} }
#print "\n raw: <" . unpack('H*', $data) . ">\n";
$data = $this->decrypt($data); $data = $this->decrypt($data);
#print "clear: <" . unpack('H*', $data) . ">\n";
my $len = unpack("L<", substr($data, 0, 4)); my $len = unpack("L<", substr($data, 0, 4));
my $type = unpack("C", substr($data, 4, 1)); my $type = unpack("C", substr($data, 4, 1));
my $raw = substr($data, 5); my $raw = substr($data, 5);
#print "readfield: len: $len, type: $type\n";
if ($len > 11) { if ($len > 11) {
my $step = int(($len+4) / 16); my $step = int(($len+4) / 16);
for (1 .. $step) { for (1 .. $step) {
@@ -623,10 +614,10 @@ sub readfield {
} }
$raw = substr($raw, 0, $len); $raw = substr($raw, 0, $len);
if ($header) { if ($header) {
return new Crypt::PWSafe3::HeaderField(type => $type, raw => $raw); return Crypt::PWSafe3::HeaderField->new(type => $type, raw => $raw);
} }
else { else {
return new Crypt::PWSafe3::Field(type => $type, raw => $raw); return Crypt::PWSafe3::Field->new(type => $type, raw => $raw);
} }
} }
@@ -646,7 +637,7 @@ sub encrypt {
my $raw = $this->{cipher}->encrypt($data); my $raw = $this->{cipher}->encrypt($data);
if (length($raw) > 16) { if (length($raw) > 16) {
# we use only the last 16byte block as next iv # we use only the last 16byte block as next iv
# if data is more than 1 blocks than Crypt::CBC # if data is more than 1 blocks then Crypt::CBC
# has already updated the iv for the inner blocks # has already updated the iv for the inner blocks
$raw = substr($raw, -16, 16); $raw = substr($raw, -16, 16);
} }
@@ -672,7 +663,6 @@ sub readbytes {
my $got = $this->{fd}->sysread($buffer, $size); my $got = $this->{fd}->sysread($buffer, $size);
if ($got == $size) { if ($got == $size) {
$this->{sum} += $got; $this->{sum} += $got;
#print "Got $got bytes (read so far: $this->{sum} bytes) $package line $line\n";
return $buffer; return $buffer;
} }
else { else {
@@ -698,7 +688,6 @@ sub getheader {
# #
# return a header object # return a header object
my($this, $name) = @_; my($this, $name) = @_;
# $this->{header}->{ $field->name } = $field;
if (exists $this->{header}->{$name}) { if (exists $this->{header}->{$name}) {
return $this->{header}->{$name}; return $this->{header}->{$name};
} }
@@ -717,7 +706,7 @@ Crypt::PWSafe3 - Read and write Passwordsafe v3 files
=head1 SYNOPSIS =head1 SYNOPSIS
use Crypt::PWSafe3; use Crypt::PWSafe3;
my $vault = new Crypt::PWSafe3(file => 'filename.psafe3', password => 'somesecret'); my $vault = Crypt::PWSafe3->new(file => 'filename.psafe3', password => 'somesecret');
# fetch all database records # fetch all database records
my @records = $vault->getrecords(); my @records = $vault->getrecords();
@@ -764,7 +753,7 @@ Crypt::PWSafe3 - Read and write Passwordsafe v3 files
print scalar localtime($vault->getheader('lastsavetime')->value()); print scalar localtime($vault->getheader('lastsavetime')->value());
# add/replace a database header # add/replace a database header
my $h = new Crypt::PWSafe3::HeaderField(name => 'savedonhost', value => 'localhost'); my $h = Crypt::PWSafe3::HeaderField->new(name => 'savedonhost', value => 'localhost');
$vault->addheader($h); $vault->addheader($h);
=head1 DESCRIPTION =head1 DESCRIPTION
@@ -780,11 +769,12 @@ http://passwordsafe.sf.net.
The new() method creates a new Crypt::PWSafe3 object. Any parameters The new() method creates a new Crypt::PWSafe3 object. Any parameters
must be given as hash parameters. must be given as hash parameters.
my $vault = new Crypt::PWSafe3( my $vault = Crypt::PWSafe3->new(
file => 'vault.psafe3', file => 'vault.psafe3',
password => 'secret', password => 'secret',
whoami => 'user1', whoami => 'user1',
program => 'mypwtool v1' program => 'mypwtool v1',
create => 0, # or 1
); );
Mandatory parameters: Mandatory parameters:
@@ -820,6 +810,11 @@ If omitted, the content of the perl variable $0 will
be used, which contains the name of the current running be used, which contains the name of the current running
script. script.
=item B<create>
If set to 0, B<new()> will fail if the file doesn't exist,
otherwise it will try to create it. Enabled by default.
=back =back
The optional parameters will become header fields of The optional parameters will become header fields of
@@ -882,6 +877,16 @@ The parameter hash may contain any valid record field
type with according values. Refer to L<Crypt::PWSafe3::Record> type with according values. Refer to L<Crypt::PWSafe3::Record>
for details about available fields. for details about available fields.
=head2 B<newrecord(parameter-hash)>
Create a new record. The UUID of the record will be generated
automatically. Refer to L<Crypt::PWSafe3::Record>
for details about available fields.
=head2 B<addrecord(Crypt::PWSafe3::Record object)>
Add a record to the vault. The record must be an
L<Crypt::PWSafe3::Record> object.
=head2 B<deleterecord(uuid)> =head2 B<deleterecord(uuid)>
@@ -970,7 +975,7 @@ License 2.0, see: L<http://www.perlfoundation.org/artistic_license_2_0>
=head1 VERSION =head1 VERSION
Crypt::PWSafe3 Version 1.16. Crypt::PWSafe3 Version 1.17.
=cut =cut

View File

@@ -13,7 +13,7 @@ use Exporter ();
use vars qw(@ISA @EXPORT); use vars qw(@ISA @EXPORT);
use utf8; use utf8;
$Crypt::PWSafe3::Field::VERSION = '1.05'; $Crypt::PWSafe3::Field::VERSION = '1.06';
%Crypt::PWSafe3::Field::map2type = ( %Crypt::PWSafe3::Field::map2type = (
uuid => 0x01, uuid => 0x01,
@@ -120,9 +120,6 @@ sub new {
$self->{name} = $self->{type}; $self->{name} = $self->{type};
} }
#print "New Field of type $self->{name}\n";
#print "Field Value: $self->{value}\n";
return $self; return $self;
} }
@@ -151,7 +148,7 @@ raw implementation and you normally don't have to cope with it.
However, if you ever do, you can do it this way: However, if you ever do, you can do it this way:
my $field = new Crypt::PWSafe3::Field( my $field = Crypt::PWSafe3::Field->new(
value => 'testing', value => 'testing',
name => 'title name => 'title
); );

View File

@@ -13,7 +13,7 @@ use Exporter ();
use vars qw(@ISA @EXPORT); use vars qw(@ISA @EXPORT);
use utf8; use utf8;
$Crypt::PWSafe3::HeaderField::VERSION = '1.04'; $Crypt::PWSafe3::HeaderField::VERSION = '1.05';
%Crypt::PWSafe3::HeaderField::map2name = ( %Crypt::PWSafe3::HeaderField::map2name = (
0x00 => "version", 0x00 => "version",
@@ -135,7 +135,7 @@ Crypt::PWSafe3::HeaderField - represent a passwordsafe v3 header field.
my $who = $vault->getheader('wholastsaved'); my $who = $vault->getheader('wholastsaved');
print $who->value; print $who->value;
my $h = new Crypt::PWSafe3::HeaderField(name => 'savedonhost', my $h = Crypt::PWSafe3::HeaderField->new(name => 'savedonhost',
value => 'localhost'); value => 'localhost');
$vault->addheader($h); $vault->addheader($h);
@@ -147,7 +147,7 @@ raw implementation and you normally don't have to cope with it.
However, if you ever do, you can add/replace any field type However, if you ever do, you can add/replace any field type
this way: this way:
my $field = new Crypt::PWSafe3::HeaderField( my $field = Crypt::PWSafe3::HeaderField->new(
value => 'localhost', value => 'localhost',
name => 'savedonhost' name => 'savedonhost'
); );

View File

@@ -15,7 +15,7 @@ my %map2type = %Crypt::PWSafe3::Field::map2type;
my %map2name = %Crypt::PWSafe3::Field::map2name; my %map2name = %Crypt::PWSafe3::Field::map2name;
$Crypt::PWSafe3::Record::VERSION = '1.08'; $Crypt::PWSafe3::Record::VERSION = '1.09';
foreach my $field (keys %map2type ) { foreach my $field (keys %map2type ) {
eval qq( eval qq(
@@ -46,50 +46,50 @@ sub new {
my $time = time; my $time = time;
$self->addfield(new Crypt::PWSafe3::Field( $self->addfield(Crypt::PWSafe3::Field->new(
name => 'uuid', name => 'uuid',
raw => $newuuid, raw => $newuuid,
));
$self->addfield(Crypt::PWSafe3::Field->new(
name => 'ctime',
value => $time,
));
$self->addfield(Crypt::PWSafe3::Field->new(
name => 'mtime',
value => $time
));
$self->addfield(Crypt::PWSafe3::Field->new(
name => 'lastmod',
value => $time
));
$self->addfield(Crypt::PWSafe3::Field->new(
name => 'passwd',
value => ''
));
$self->addfield(Crypt::PWSafe3::Field->new(
name => 'user',
value => ''
)); ));
$self->addfield(new Crypt::PWSafe3::Field( $self->addfield(Crypt::PWSafe3::Field->new(
name => 'ctime', name => 'title',
value => $time, value => ''
)); ));
$self->addfield(new Crypt::PWSafe3::Field( $self->addfield(Crypt::PWSafe3::Field->new(
name => 'mtime', name => 'notes',
value => $time value => ''
)); ));
$self->addfield(new Crypt::PWSafe3::Field(
name => 'lastmod',
value => $time
));
$self->addfield(new Crypt::PWSafe3::Field( $self->addfield(Crypt::PWSafe3::Field->new(
name => 'passwd', name => 'group',
value => '' value => ''
)); ));
$self->addfield(new Crypt::PWSafe3::Field(
name => 'user',
value => ''
));
$self->addfield(new Crypt::PWSafe3::Field(
name => 'title',
value => ''
));
$self->addfield(new Crypt::PWSafe3::Field(
name => 'notes',
value => ''
));
$self->addfield(new Crypt::PWSafe3::Field(
name => 'group',
value => ''
));
return $self; return $self;
} }
@@ -100,7 +100,7 @@ sub modifyfield {
my($this, $name, $value) = @_; my($this, $name, $value) = @_;
if (exists $map2type{$name}) { if (exists $map2type{$name}) {
my $type = $map2type{$name}; my $type = $map2type{$name};
my $field = new Crypt::PWSafe3::Field( my $field = Crypt::PWSafe3::Field->new(
type => $type, type => $type,
value => $value value => $value
); );
@@ -114,15 +114,15 @@ sub modifyfield {
$this->addfield($field); $this->addfield($field);
# mark the field as modified if it's passwd field # mark the field as modified if it's passwd field
$this->addfield(new Crypt::PWSafe3::Field( $this->addfield(Crypt::PWSafe3::Field->new(
name => 'mtime', name => 'mtime',
value => $time value => $time
)) if $name eq 'passwd'; )) if $name eq 'passwd';
$this->addfield(new Crypt::PWSafe3::Field( $this->addfield(Crypt::PWSafe3::Field->new(
name => "lastmod", name => "lastmod",
value => $time value => $time
)); ));
return $field; return $field;
} }
else { else {
@@ -134,7 +134,7 @@ sub genuuid {
# #
# generate a v4 uuid string # generate a v4 uuid string
my($this) = @_; my($this) = @_;
my $ug = new Data::UUID; my $ug = Data::UUID->new();
my $uuid = $ug->create(); my $uuid = $ug->create();
return $uuid; return $uuid;
} }

View File

@@ -8,7 +8,7 @@
package Crypt::PWSafe3::SHA256; package Crypt::PWSafe3::SHA256;
$Crypt::PWSafe3::SHA256::VERSION = '1.02'; $Crypt::PWSafe3::SHA256::VERSION = '1.03';
use Digest::SHA; use Digest::SHA;
@@ -17,7 +17,7 @@ sub new {
my $class = ref($this) || $this; my $class = ref($this) || $this;
my $self = { }; my $self = { };
bless($self, $class); bless($self, $class);
my $sha = new Digest::SHA('SHA-256'); my $sha = Digest::SHA->new('SHA-256');
return $sha; return $sha;
} }

87
t/run.t
View File

@@ -12,9 +12,24 @@
# #
use Data::Dumper; use Data::Dumper;
#use Test::More tests => 57; use Test::More tests => 11;
use Test::More qw(no_plan); #use Test::More qw(no_plan);
my %params = (create => 0, password => 'tom');
my %record = (
user => 'u3',
passwd => 'p3',
group => 'g3',
title => 't3',
notes => 'n3'
);
sub rdpw {
my $file = shift;
my $vault = Crypt::PWSafe3->new(file => $file, %params) or die "$!";
return $vault;
}
### 1 ### 1
# load module # load module
@@ -24,7 +39,7 @@ require_ok( 'Crypt::PWSafe3' );
### 2 ### 2
# open vault and read in all records # open vault and read in all records
eval { eval {
my $vault = new Crypt::PWSafe3(file => 't/tom.psafe3', password => 'tom'); my $vault = &rdpw('t/tom.psafe3');
my @r = $vault->getrecords; my @r = $vault->getrecords;
my $got = 0; my $got = 0;
foreach my $rec (@r) { foreach my $rec (@r) {
@@ -36,47 +51,67 @@ eval {
die "No records found in test database"; die "No records found in test database";
} }
}; };
ok(!$@, "open a pwsafe3 database"); ok(!$@, "open a pwsafe3 database ($@)");
### 1a
# create a new vault
my %rdata1a;
my $fd = File::Temp->new(TEMPLATE => '.myvaultXXXXXXXX', TMPDIR => 1, EXLOCK => 0) or die "Could not open tmpfile: $!\n";
my $tmpfile = "$fd";
close($fd);
eval {
my $vault = Crypt::PWSafe3->new(file => $tmpfile, password => 'tom') or die "$!";
$vault->newrecord(%record);
$vault->save();
};
ok(!$@, "create a new pwsafe3 database ($@)");
eval {
my $rvault1a = &rdpw($tmpfile);
my $rec1a = ($rvault1a->getrecords())[0];
foreach my $name (keys %record) {
$rdata1a{$name} = $rec1a->$name();
}
};
ok(!$@, "read created new pwsafe3 database ($@)");
is_deeply(\%record, \%rdata1a, "Write record to a new pwsafe3 database");
unlink($tmpfile);
### 3 ### 3
# modify an existing record # modify an existing record
my $uuid3; my $uuid3;
my %rdata3; my %rdata3;
my $rec3; my $rec3;
my %data3 = (
user => 'u3',
passwd => 'p3',
group => 'g3',
title => 't3',
notes => 'n3'
);
eval { eval {
my $vault3 = new Crypt::PWSafe3(file => 't/tom.psafe3', password => 'tom'); my $vault3 = &rdpw('t/tom.psafe3');
foreach my $uuid ($vault3->looprecord) { foreach my $uuid ($vault3->looprecord) {
$uuid3 = $uuid; $uuid3 = $uuid;
$vault3->modifyrecord($uuid3, %data3); $vault3->modifyrecord($uuid3, %record);
last; last;
} }
$vault3->save(file=>'t/3.out'); $vault3->save(file=>'t/3.out');
my $rvault3 = new Crypt::PWSafe3(file => 't/3.out', password => 'tom'); my $rvault3 = &rdpw('t/3.out');
$rec3 = $rvault3->getrecord($uuid3); $rec3 = $rvault3->getrecord($uuid3);
foreach my $name (keys %data3) { foreach my $name (keys %record) {
$rdata3{$name} = $rec3->$name(); $rdata3{$name} = $rec3->$name();
} }
}; };
ok(!$@, "read a pwsafe3 database and change a record ($@)"); ok(!$@, "read a pwsafe3 database and change a record ($@)");
is_deeply(\%data3, \%rdata3, "Change a record an check if changes persist after saving"); is_deeply(\%record, \%rdata3, "Change a record an check if changes persist after saving");
### 4 ### 4
# re-use $rec3 and change it the oop way # re-use $rec3 and change it the oop way
my $rec4; my $rec4;
eval { eval {
my $vault4 = new Crypt::PWSafe3(file => 't/3.out', password => 'tom'); my $vault4 = &rdpw('t/tom.psafe3');
$rec4 = $vault4->getrecord($uuid3); $rec4 = $vault4->getrecord($uuid3);
$rec4->user("u4"); $rec4->user("u4");
$rec4->passwd("p4"); $rec4->passwd("p4");
@@ -84,7 +119,7 @@ eval {
$vault4->markmodified(); $vault4->markmodified();
$vault4->save(file=>'t/4.out'); $vault4->save(file=>'t/4.out');
my $rvault4 = new Crypt::PWSafe3(file => 't/4.out', password => 'tom'); my $rvault4 = &rdpw('t/4.out');
$rec4 = $rvault4->getrecord($uuid3); $rec4 = $rvault4->getrecord($uuid3);
if ($rec4->user ne 'u4') { if ($rec4->user ne 'u4') {
die "oop way record change failed"; die "oop way record change failed";
@@ -95,7 +130,7 @@ ok(!$@, "re-use record and change it the oop way\n" . $@ . "\n");
### 5 modify some header fields ### 5 modify some header fields
eval { eval {
my $vault5 = new Crypt::PWSafe3(file => 't/tom.psafe3', password => 'tom'); my $vault5 = &rdpw('t/tom.psafe3');
my $h3 = new Crypt::PWSafe3::HeaderField(name => 'savedonhost', value => 'localhost'); my $h3 = new Crypt::PWSafe3::HeaderField(name => 'savedonhost', value => 'localhost');
@@ -103,7 +138,7 @@ eval {
$vault5->markmodified(); $vault5->markmodified();
$vault5->save(file=>'t/5.out'); $vault5->save(file=>'t/5.out');
my $rvault5 = new Crypt::PWSafe3(file => 't/5.out', password => 'tom'); my $rvault5 = &rdpw('t/5.out');
if ($rvault5->getheader('savedonhost')->value() ne 'localhost') { if ($rvault5->getheader('savedonhost')->value() ne 'localhost') {
die "header savedonhost not correct"; die "header savedonhost not correct";
@@ -113,11 +148,11 @@ ok(!$@, "modify some header fields ($@)");
### 6 delete ### 6 delete
eval { eval {
my $vault6 = new Crypt::PWSafe3(file => 't/3.out', password => 'tom'); my $vault6 = &rdpw('t/3.out');
my $uuid = $vault6->newrecord(user => 'xxx', passwd => 'y'); my $uuid = $vault6->newrecord(user => 'xxx', passwd => 'y');
$vault6->save(file=>'t/6.out'); $vault6->save(file=>'t/6.out');
my $rvault6 = new Crypt::PWSafe3(file => 't/6.out', password => 'tom'); my $rvault6 = &rdpw('t/6.out');
my $rec = $rvault6->getrecord($uuid); my $rec = $rvault6->getrecord($uuid);
if ($rec->user ne 'xxx') { if ($rec->user ne 'xxx') {
die "oop way record change failed"; die "oop way record change failed";
@@ -127,8 +162,8 @@ eval {
die "deleted record still present in open vault"; die "deleted record still present in open vault";
} }
$vault6->save(file=>'t/6a.out'); $vault6->save(file=>'t/6a.out');
my $rvault6a = new Crypt::PWSafe3(file => 't/6a.out', password => 'tom'); my $rvault6a = &rdpw('t/6a.out');
if ($rvault6->getrecord($uuid)) { if ($rvault6->getrecord($uuid)) {
die "deleted record reappears after save and reload"; die "deleted record reappears after save and reload";
} }