AnyEvent-Yubico
view release on metacpan or search on metacpan
lib/AnyEvent/Yubico.pm view on Meta::CPAN
my $self = {
sign_request => 1,
local_timeout => 30.0,
urls => [
"https://api.yubico.com/wsapi/2.0/verify",
"https://api2.yubico.com/wsapi/2.0/verify",
"https://api3.yubico.com/wsapi/2.0/verify",
"https://api4.yubico.com/wsapi/2.0/verify",
"https://api5.yubico.com/wsapi/2.0/verify"
]
};
my $options = shift;
$self = { %$self, %$options };
return bless $self, $class;
};
# Verifies the given OTP and returns a true value if the OTP could be
# verified, false otherwise.
sub verify {
return verify_async(@_)->recv->{status} eq 'OK';
}
# Verifies the given OTP and returns a hash containing the server response.
sub verify_sync {
return verify_async(@_)->recv
}
# Non-blocking version of verify_sync, which returns a condition variable
# (see AnyEvent->condvar for details).
sub verify_async {
my($self, $otp, $callback) = @_;
my $nonce = create_UUID_as_string(UUID_V4);
$nonce =~ s/-//g;
my $params = {
id => $self->{client_id},
nonce => $nonce,
otp => $otp
};
if(exists $self->{timeout}) {
$params->{timeout} = $self->{timeout};
}
if(exists $self->{sl}) {
$params->{sl} = $self->{sl};
}
if($self->{timestamp}) {
$params->{timestamp} = 1;
}
if($self->{sign_request} and !$self->{api_key} eq '') {
$params->{h} = $self->sign($params);
}
my $query = "";
for my $key (keys %$params) {
$query = "$query&$key=".uri_escape($params->{$key});
}
$query = "?".substr($query, 1);
my $last_response;
my @requests = ();
my $result_var = AnyEvent->condvar(cb => $callback);
my $inner_var = AnyEvent->condvar(cb => sub {
my $result = shift->recv;
foreach my $req (@requests) {
undef $req;
}
if(exists $result->{status}) {
$result_var->send($result);
} elsif(exists $last_response->{status}) {
#All responses returned replayed request.
$result_var->send($last_response);
} else {
#Didn't get any valid responses.
$result_var->croak("No valid response!");
}
});
foreach my $url (@{$self->{urls}}) {
$inner_var->begin();
push(@requests, http_get("$url$query",
timeout => $self->{local_timeout},
tls_ctx => 'high',
sub {
my($body, $hdr) = @_;
if(not $hdr->{Status} =~ /^2/) {
#Error, store message if none exists.
if(not exists $last_response->{status}) {
$last_response->{status} = $hdr->{Reason};
}
$inner_var->end();
return;
}
my $response = parse_response($body);
if(! exists $response->{status}) {
#Response does not look valid, discard.
$inner_var->end();
return;
}
if(! $self->{api_key} eq '') {
my $signature = $response->{h};
delete $response->{h};
if(! $signature eq $self->sign($response)) {
$response->{status} = "BAD_RESPONSE_SIGNATURE";
}
}
$last_response = $response;
if($response->{status} eq "REPLAYED_REQUEST") {
( run in 0.625 second using v1.01-cache-2.11-cpan-13bb782fe5a )