aboutsummaryrefslogtreecommitdiff
path: root/lib/Net/Hawk/Client.pm
blob: deec11df1d46ea0b752d88aafaff9593e9571aba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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;