aboutsummaryrefslogtreecommitdiff
path: root/lib/Net/Hawk/Client.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Net/Hawk/Client.pm')
-rw-r--r--lib/Net/Hawk/Client.pm92
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/Net/Hawk/Client.pm b/lib/Net/Hawk/Client.pm
new file mode 100644
index 0000000..deec11d
--- /dev/null
+++ b/lib/Net/Hawk/Client.pm
@@ -0,0 +1,92 @@
+package Net::Hawk::Client;
+use strict;
+use warnings;
+use 5.010;
+use Moo;
+use Types::Standard 1.000003 qw(Str Int Object Dict Optional Undef Any HasMethods slurpy);
+use Types::URI qw(Uri);
+use Type::Params qw(compile);
+use Try::Tiny;
+use Net::Hawk::Utils;
+use Session::Token;
+use Net::Hawk::Role::WithUtils;
+use Net::Hawk::Role::WithCrypto;
+
+with WithUtils(qw(now_secs));
+with WithCrypto(qw(calculate_payload_hash));
+
+sub header {
+ state $argcheck = compile(Object,Uri,Str,Dict[
+ timestamp => Optional[Int],
+ localtime_offset_msec => Optional[Int],
+ credentials => Dict[
+ id => Str,
+ key => Str,
+ algorithm => Str,
+ ],
+ nonce => Optional[Str],
+ hash => Optional[Str],
+ ext => Optional[Str],
+ app => Optional[Str],
+ dlg => Optional[Str],
+ payload => Optional[Str],
+ content_type => Optional[Str],
+ slurpy Any,
+ ]);
+ my ($self,$uri,$method,$options) = $argcheck->(@_);
+
+ my $timestamp = $options->{timestamp} //
+ $self->_utils->now_secs($options->{localtime_offset_msec});
+
+ my $credentials = $options->{credentials};
+
+ my %artifacts = (
+ ts => $timestamp,
+ nonce => $options->{nonce} || Session::Token->new->get,
+ method => $method,
+ resource => $uri->path_query,
+ host => $uri->host,
+ port => $uri->port // ($uri->scheme eq 'http:' ? 80 : 443),
+ );
+ for my $k (qw(hash ext app dlg)) {
+ next unless defined $options->{$k};
+ $artifacts{$k} = $options->{$k};
+ }
+
+ if ( !$artifacts{hash} && defined $options->{payload} ) {
+ $artifacts{hash} = $self->_crypto->calculate_payload_hash(
+ $options->{payload},
+ $credentials->{algorithm},
+ $options->{content_type},
+ );
+ }
+
+ my $mac = $self->_crypto->calculate_mac(header=>$credentials,\%artifacts);
+
+ my $has_ext = ($options->{ext}//'') ne '';
+
+ my $header = sprintf(
+ 'Hawk id="%s", ts="%d", nonce="%s"',
+ $credentials->{id},
+ $artifacts{ts},
+ $artifacts{nonce},
+ )
+ . ($artifacts{hash} ? sprintf(', hash="%s"',$artifacts{hash}) : '')
+ . ($has_ext ? sprintf(', ext="%s"', $artifacts{ext} =~ s{([\\"])}{\\$1}gr) : '' )
+ . sprintf(', mac="%s"',$mac);
+
+ if ($artifacts{app}) {
+ $header .= sprintf(', app="%s"', $artifacts{app});
+ if ($artifacts{dlg}) {
+ $header .= sprintf(', dlg="%s"',$artifacts{dlg});
+ }
+ }
+
+ return {
+ field => $header,
+ artifacts => \%artifacts,
+ };
+}
+
+
+1;