File Coverage

lib/Auth/YubiKey/Client/Web/Response.pm
Criterion Covered Total %
statement 9 47 19.1
branch 0 14 0.0
condition n/a
subroutine 3 9 33.3
pod 5 5 100.0
total 17 75 22.6


line stmt bran cond sub pod time code
1             package Auth::YubiKey::Client::Web::Response;
2             {
3             $Auth::YubiKey::Client::Web::Response::DIST = 'Auth-YubiKey-Client-Web';
4             }
5             $Auth::YubiKey::Client::Web::Response::VERSION = '0.0.2';
6 1     1   37614 use Moo;
  1         15567  
  1         7  
7 1     1   2494 use Digest::HMAC_SHA1 'hmac_sha1';
  1         1723665  
  1         65  
8 1     1   786 use MIME::Base64;
  1         712264  
  1         852  
9              
10              
11             has request_apikey => (
12             is => 'ro',
13             required => 1,
14             );
15              
16             has request_otp => (
17             is => 'ro',
18             required => 1,
19             );
20              
21             has request_nonce => (
22             is => 'ro',
23             required => 1,
24             );
25              
26             has request_response => (
27             is => 'ro',
28             required => 1,
29             );
30              
31             has h => (
32             is => 'rw'
33             );
34              
35             has t => (
36             is => 'rw'
37             );
38              
39             has otp => (
40             is => 'rw'
41             );
42              
43             has nonce => (
44             is => 'rw'
45             );
46              
47             has sl => (
48             is => 'rw'
49             );
50              
51             has status => (
52             is => 'rw'
53             );
54              
55             has public_id => (
56             is => 'rw',
57             );
58              
59             has datastring => (
60             is => 'rw',
61             );
62              
63              
64             sub BUILDARGS {
65 0     0 1   my ( $class, @args ) = @_;
66 0 0         unshift @args, "attr1" if @args % 2 == 1;
67              
68             # store response keys (for later verifying the response signature 'h'
69 0           my %response_for;
70              
71             # run through the response blob; extract key=val data
72             # - add key, val to @args for object initialisation
73             # - store the key, val for later building and verifying the signature
74 0           foreach my $line (split(/\n/,{@args}->{request_response})) {
75 0 0         if ($line =~ /=/) {
76 0           $line =~ s/\s//g;
77 0           my ($key,$val) = split(/=/,$line,2);
78 0           $response_for{$key}=$val;
79 0           push @args, $key, $val;
80             }
81             }
82              
83             # store the generated response line
84 0           push @args, 'datastring', _build_datastring(\%response_for);
85              
86 0           return {@args};
87             }
88              
89             sub _build_datastring {
90 0     0     my $response_for = shift;
91 0           my @response_blobs;
92              
93 0           foreach my $key (sort keys %{$response_for}) {
  0            
94 0 0         next if $key eq 'h'; # don't include the signature itself
95             push @response_blobs,
96             sprintf('%s=%s',
97             $key,
98 0           $response_for->{$key}
99             )
100             ;
101             }
102            
103 0           return join('&', @response_blobs);
104             }
105              
106             sub BUILD {
107 0     0 1   my $self = shift;
108              
109 0 0         return if $self->status eq 'NO_SUCH_CLIENT';
110              
111 0 0         if ($self->otp ne $self->request_otp) {
112 0           $self->status('ERR_MSG_OTP');
113 0           return;
114             }
115              
116 0 0         if ($self->nonce ne $self->request_nonce) {
117 0           $self->status('ERR_MSG_NONCE');
118 0           return;
119             }
120              
121 0           my $hmac = encode_base64(
122             hmac_sha1(
123             $self->datastring,
124             decode_base64($self->request_apikey)
125             )
126             );
127 0           chomp $hmac;
128              
129 0 0         if ($self->h ne $hmac) {
130 0           $self->status('ERR_SIGNATURE_MISMATCH');
131 0           return;
132             }
133              
134             # Since the rest of the OTP is always 32 characters, the method to extract
135             # the identity is to remove 32 characters from the end and then use the
136             # remaining string, which should be 2-16 characters, as the YubiKey
137             # identity.
138             $self->public_id(
139 0           substr $self->otp, 0, -32
140             );
141             }
142              
143              
144             sub is_success {
145 0     0 1   my $self = shift;
146 0           return !!($self->status eq 'OK');
147             }
148              
149             sub is_error {
150 0     0 1   my $self = shift;
151 0           return !!($self->status ne 'OK');
152             }
153              
154             sub parse_response {
155 0     0 1   my $self = shift;
156 0           my $response = shift;
157             }
158              
159             1;
160             # ABSTRACT: Response object when using the Yubico Web API
161              
162             =pod
163              
164             =encoding UTF-8
165              
166             =head1 NAME
167              
168             Auth::YubiKey::Client::Web::Response - Response object when using the Yubico Web API
169              
170             =head1 VERSION
171              
172             version 0.0.2
173              
174             =head1 CLASS ATTRIBUTES
175              
176             =head2 request_apikey
177              
178             =head2 request_otp
179              
180             =head2 request_nonce
181              
182             =head2 request_response
183              
184             =head2 h
185              
186             =head2 t
187              
188             =head2 otp
189              
190             =head2 nonce
191              
192             =head2 sl
193              
194             =head2 status
195              
196             =head2 public_id
197              
198             =head2 datastring
199              
200             =head1 PRIVATE METHODS
201              
202             =head2 BUILDARGS
203              
204             =head2 BUILD
205              
206             =head1 METHODS
207              
208             =head2 is_success
209              
210             =head2 is_error
211              
212             =head2 parse_response
213              
214             Nothing implemented.
215              
216             =head1 AUTHOR
217              
218             Chisel
219              
220             =head1 COPYRIGHT AND LICENSE
221              
222             This software is copyright (c) 2013 by Chisel Wright.
223              
224             This is free software; you can redistribute it and/or modify it under
225             the same terms as the Perl 5 programming language system itself.
226              
227             =cut
228              
229             __END__