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 )