my
@tests
= (
{
'crypted'
=>
'$2a$10$O0fG6ExZRx4mEZxsRHqPKuDy9U2HW9M4UONC1hnsx84tW/bb5URFO'
,
'algo'
=> 1,
'options'
=> {},
'expect'
=> 1,
'reason'
=>
'algorithm signature is not 2y'
,
},
{
'crypted'
=>
'$2b$10$wOmSB/8mvcXJBAnPTJzO..tFOq4nCxP21vTfWqunrVi5Irsi3Obcy'
,
'algo'
=> 1,
'options'
=> {
'cost'
=> 10,
'salt'
=>
'wOmSB/8mvcXJBAnPTJzO..'
,
},
'expect'
=> 1,
'reason'
=>
'algorithm signature is not 2y'
,
},
{
'crypted'
=>
'$2y$04$f5VgvyHCr0OiPbvjdZ8zJuPBHD6Tul6nleZSWUVkk/HSOKOC8DmFy'
,
'algo'
=> 1,
'options'
=> {
'cost'
=> 4,
},
'expect'
=> 0,
'reason'
=>
'up to date'
,
},
{
'crypted'
=>
'$2y$04$f5VgvyHCr0OiPbvjdZ8zJuPBHD6Tul6nleZSWUVkk/HSOKOC8DmFy'
,
'algo'
=> 1,
'options'
=> {
},
'expect'
=> 1,
'reason'
=>
'cost is not the default (10)'
,
},
{
'crypted'
=>
'$2y$10$wOmSB/8mvcXJBAnPTJzO..tFOq4nCxP21vTfWqunrVi5Irsi3Obcy'
,
'algo'
=> 1,
'options'
=> {
'cost'
=> 5,
},
'expect'
=> 1,
'reason'
=>
'cost changed'
,
},
{
'crypted'
=>
'$2y$10$wOmSB/8mvcXJBAnPTJzO..tFOq4nCxP21vTfWqunrVi5Irsi3Obcy'
,
'algo'
=> 1,
'options'
=> {
'salt'
=>
'f5VgvyHCr0OiPbvjdZ8zJu'
,
},
'expect'
=> 0,
'reason'
=>
'salt options are ignored'
,
},
{
'crypted'
=>
'yabadabadoo'
,
'algo'
=> 0,
'options'
=> {},
'expect'
=> 1,
'reason'
=>
'unknown algorithm given'
,
},
{
'crypted'
=>
'yabadabadoo'
,
'algo'
=> 1,
'options'
=> {},
'expect'
=> 1,
'expect_php'
=> 1,
'reason'
=>
'invalid crypt string'
,
},
{
'crypted'
=>
'$argon2id$v=19$m=65536,t=4,p=1$ZExWOUovRW1YNldkNFNsZA$2VI1DHxtqj3gQgVC5M3SZnYXZD4rM1mJR9666QVGCkQ'
,
'algo'
=> 3,
'options'
=> {
'memory_cost'
=> 65536,
'time_cost'
=> 4,
'threads'
=> 1,
},
'expect'
=> 0,
'reason'
=>
'up to date'
,
},
{
'crypted'
=>
'$argon2id$v=19$m=65536,t=4,p=1$ZExWOUovRW1YNldkNFNsZA$2VI1DHxtqj3gQgVC5M3SZnYXZD4rM1mJR9666QVGCkQ'
,
'algo'
=> 3,
'options'
=> {
'memory_cost'
=> 65536,
'time_cost'
=> 8,
'threads'
=> 1,
},
'expect'
=> 1,
'reason'
=>
'time_cost mismatch'
,
},
{
'crypted'
=>
'$argon2id$v=19$m=65536,t=4,p=1$ZExWOUovRW1YNldkNFNsZA$2VI1DHxtqj3gQgVC5M3SZnYXZD4rM1mJR9666QVGCkQ'
,
'algo'
=> 3,
'options'
=> {
'memory_cost'
=> 123,
'time_cost'
=> 4,
'threads'
=> 1,
},
'expect'
=> 1,
'reason'
=>
'memory_cost mismatch'
,
},
{
'crypted'
=>
'$argon2id$v=19$m=65536,t=4,p=1$ZExWOUovRW1YNldkNFNsZA$2VI1DHxtqj3gQgVC5M3SZnYXZD4rM1mJR9666QVGCkQ'
,
'algo'
=> 3,
'options'
=> {
'memory_cost'
=> 65536,
'time_cost'
=> 4,
'threads'
=> 2,
},
'expect'
=> 1,
'reason'
=>
'threads mismatch'
,
},
);
my
@methods
=
map
{
$_
,
"password_$_"
; }
qw(
needs_rehash
)
;
my
$php
;
if
(!(
$ENV
{
'HARNESS_ACTIVE'
} || ($^O eq
'MSWin32'
))) {
$php
= `which php`;
$php
=~ s/^\s+|\s+$//g;
if
(-x
$php
) {
my
$phpversion
= `php -v`;
$phpversion
=~ s/^PHP (\S+)\s.*/$1/s;
my
$too_old
;
if
(
$phpversion
=~ /^(\d{1,3}\.\d{1,6})\b/) {
if
($1 < 7.3) {
$too_old
= 1;
}
}
diag(
"Found PHP executable $php with version $phpversion: "
. (
$too_old
?
'TOO OLD'
:
'OK'
) .
"\n"
);
if
(
$too_old
) {
undef
(
$php
);
}
}
else
{
undef
(
$php
);
}
}
plan
tests
=> 1 +
scalar
(
@methods
) + (
$php
? 3 : 2) *
scalar
(
@tests
);
my
$class
=
'PHP::Functions::Password'
;
use_ok(
$class
) || BAIL_OUT(
"Failed to use $class"
);
foreach
my
$method
(
@methods
) {
can_ok(
$class
,
$method
);
if
(
$method
=~ /^password/) {
$class
->
import
(
$method
);
}
}
foreach
my
$test
(
@tests
) {
my
$crypted
=
$test
->{
'crypted'
};
my
$algo
=
$test
->{
'algo'
};
my
$options
=
$test
->{
'options'
};
my
$expect
=
$test
->{
'expect'
};
my
$reason
=
$test
->{
'reason'
};
my
$result
=
$class
->needs_rehash(
$crypted
,
$algo
,
$options
);
is(
$result
,
$expect
,
"Expect $expect from $class->needs_rehash(\"$crypted\",...) because $reason"
);
$result
= password_needs_rehash(
$crypted
,
$algo
,
$options
);
is(
$result
,
$expect
,
"Expect $expect from password_needs_rehash(\"$crypted\",...) because $reason"
);
if
(
$php
) {
my
$phpcode
=
"password_needs_rehash('"
.
$crypted
.
"', $algo, ["
;
if
(
defined
(
$options
->{
'salt'
})) {
$phpcode
.=
"'salt'=>'"
.
$options
->{'salt
'} . "'
,";
}
if
(
$algo
== 1) {
if
(
defined
(
$options
->{
'cost'
})) {
$phpcode
.=
"'cost'=>"
.
$options
->{
'cost'
} .
","
;
}
}
elsif
((
$algo
== 2) || (
$algo
== 3)) {
if
(
defined
(
$options
->{
'memory_cost'
})) {
$phpcode
.=
"'memory_cost'=>"
.
$options
->{
'memory_cost'
} .
","
;
}
if
(
defined
(
$options
->{
'time_cost'
})) {
$phpcode
.=
"'time_cost'=>"
.
$options
->{
'time_cost'
} .
","
;
}
if
(
defined
(
$options
->{
'threads'
})) {
$phpcode
.=
"'threads'=>"
.
$options
->{
'threads'
} .
","
;
}
}
$phpcode
.=
'])'
;
my
$h
;
open
(
$h
,
'-|'
,
$php
,
'-r'
,
"var_export($phpcode);"
) ||
die
(
"Failed to execute $php: $!"
);
my
$line
= <
$h
>;
close
(
$h
);
my
$result
=
$line
eq
'true'
? 1 : 0;
is(
$result
,
$expect
,
"Expect $expect from PHP's $phpcode because $reason"
);
}
}