line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Azure::SAS::Timestamp; |
2
|
3
|
|
|
3
|
|
207016
|
use Moo; |
|
3
|
|
|
|
|
35372
|
|
|
3
|
|
|
|
|
14
|
|
3
|
3
|
|
|
3
|
|
6316
|
use Types::Standard qw(Int Str InstanceOf); |
|
3
|
|
|
|
|
231733
|
|
|
3
|
|
|
|
|
30
|
|
4
|
3
|
|
|
3
|
|
4857
|
use Time::Piece; |
|
3
|
|
|
|
|
32022
|
|
|
3
|
|
|
|
|
14
|
|
5
|
3
|
|
|
3
|
|
1831
|
use Regexp::Common 'time'; |
|
3
|
|
|
|
|
8249
|
|
|
3
|
|
|
|
|
15
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.0.3'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
has time_piece => ( |
10
|
|
|
|
|
|
|
is => 'rw', |
11
|
|
|
|
|
|
|
isa => InstanceOf['Time::Piece'] |
12
|
|
|
|
|
|
|
); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub sas_time { |
15
|
|
|
|
|
|
|
## Azure SAS requires time in UTC, but the timestamp must be "Z", not "UTC" |
16
|
6
|
|
|
6
|
0
|
3343
|
my $self = shift; |
17
|
6
|
|
|
|
|
146
|
return $self->time_piece->strftime( '%Y-%m-%dT%TZ' ); |
18
|
|
|
|
|
|
|
} |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub epoch { |
21
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
22
|
0
|
|
|
|
|
0
|
return $self->time_piece->epoch; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
around BUILDARGS => sub { |
26
|
|
|
|
|
|
|
my ( $orig, $class, @args ) = @_; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $arg = $args[0]; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my $time_piece; |
31
|
|
|
|
|
|
|
my $int_check = Int; |
32
|
|
|
|
|
|
|
my $str_check = Str; |
33
|
|
|
|
|
|
|
my $tp_check = InstanceOf['Time::Piece']; |
34
|
|
|
|
|
|
|
my $dt_check = InstanceOf['DateTime']; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
## If the argument is an integer, assume it's an epoch stamp. |
37
|
|
|
|
|
|
|
if ( $int_check->check( $arg ) ) { |
38
|
|
|
|
|
|
|
$time_piece = Time::Piece->strptime( $arg, '%s'); |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
elsif ( $str_check->check( $arg ) ) { |
41
|
|
|
|
|
|
|
$time_piece = parse_timestamp_str( $arg ); |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
elsif ( $tp_check->check( $arg ) ) { ## If $arg is a Time::Piece object |
44
|
|
|
|
|
|
|
$time_piece = $arg; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
elsif ( $dt_check->check( $arg ) ) { |
47
|
|
|
|
|
|
|
$time_piece = Time::Piece->strptime( $arg->epoch, '%s' ); |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
else { |
50
|
|
|
|
|
|
|
die "Couldn't parse argument to Time::Piece"; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
return { time_piece => $time_piece } |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
}; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub parse_timestamp_str { |
60
|
3
|
|
|
3
|
0
|
7
|
my $str = shift; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
## NOTE: It looks like Time::Piece strptime will not support timezone by |
63
|
|
|
|
|
|
|
## name, so we can't support arguments where the zone is expressed this |
64
|
|
|
|
|
|
|
## way (for example 2020-05-10T10:00:00CST). It (maybe?) can parse an |
65
|
|
|
|
|
|
|
## offset. Also, DateTime could (of course) handle this. Of course, |
66
|
|
|
|
|
|
|
## DateTime will not handle parsing the string as well. For now, we won't |
67
|
|
|
|
|
|
|
## support alternate time zones. |
68
|
3
|
50
|
|
|
|
24
|
if ( $str =~ /^ |
69
|
|
|
|
|
|
|
(?<timestamp> # Start capture $1 |
70
|
|
|
|
|
|
|
\d{4} - \d{2} - \d{2} T \d{2}:\d{2} # Matches YYYY-MM-DDTHH:mm |
71
|
|
|
|
|
|
|
(:\d{2})? # Optionally matches :SS |
72
|
|
|
|
|
|
|
) |
73
|
|
|
|
|
|
|
(?<timezone> Z|\w{3})? ## Could have timezone or literal "Z" |
74
|
|
|
|
|
|
|
$/x |
75
|
|
|
|
|
|
|
) { |
76
|
3
|
|
|
|
|
13
|
return Time::Piece->strptime( $1, '%Y-%m-%dT%T' ); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
|
if ( $str =~ /^\d{4} - \d{2} - \d{2}$/) { ## Matches YYYY-MM-DD |
80
|
0
|
|
|
|
|
|
return Time::Piece->strptime( $str, '%Y-%m-%d' ); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
else { |
85
|
0
|
|
|
|
|
|
die("$str does not look like an iso8601 datetime"); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
1; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
__END__ |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 NAME |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Azure::SAS::Timestamp - Creating timestamps for Azure Shared Access Signatures. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head1 SYNOPSIS |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
use Azure::SAS::Timestamp; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $ast; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Using an epoch time stamp |
107
|
|
|
|
|
|
|
$ast = Azure::SAS::Timestamp->new( 1589119719 ); |
108
|
|
|
|
|
|
|
print $ast->sas_time; # 2020-05-10T14:08:39Z |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# Using a DateTime object: |
112
|
|
|
|
|
|
|
use DateTime; |
113
|
|
|
|
|
|
|
$dt = DateTime->new( |
114
|
|
|
|
|
|
|
year => 2020, |
115
|
|
|
|
|
|
|
month => 5, |
116
|
|
|
|
|
|
|
day => 10, |
117
|
|
|
|
|
|
|
hour => 13, |
118
|
|
|
|
|
|
|
minute => 12, |
119
|
|
|
|
|
|
|
second => 0 |
120
|
|
|
|
|
|
|
); |
121
|
|
|
|
|
|
|
$ast = Azure::SAS::Timestamp->new( $dt ); |
122
|
|
|
|
|
|
|
print $ast->sas_time; # 2020-05-10T13:12:00Z |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Using Time::Piece |
125
|
|
|
|
|
|
|
use Time::Piece; |
126
|
|
|
|
|
|
|
my $tp = Time::Piece->strptime( '2020-05-10T13:12:00', '%FT%T'); |
127
|
|
|
|
|
|
|
$ast = Azure::SAS::Timestamp->new( $tp ); |
128
|
|
|
|
|
|
|
print $ast->sas_time; # 2020-05-10T13:12:00Z |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head1 DESCRIPTION |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Azure::SAS::Timestamp can be used to generate validly formated timestamps to |
134
|
|
|
|
|
|
|
be used when creating an Azure SAS (Shared Access Signature). |
135
|
|
|
|
|
|
|
Azure::SAS::Timestamp supports input as seconds from epoch, L<DateTime> objects |
136
|
|
|
|
|
|
|
and L<Time::Piece> objects. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
There is only one method, `sas_time`, which is an ISO 8601 format with a 'Z' |
139
|
|
|
|
|
|
|
at the end. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
The general idea is simply to allow a bit of sugar to avoid having to look up |
142
|
|
|
|
|
|
|
the format to use and the object methods of conversion. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head1 SEE ALSO |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
L<Documentation for Shared Access Signatures |
147
|
|
|
|
|
|
|
|https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas> |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 LICENSE |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Copyright (C) Ben Kaufman. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under |
154
|
|
|
|
|
|
|
the same terms as Perl itself. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 AUTHOR |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Ben Kaufman (WHOSGONNA) ben.whosgonna.com@gmail.com |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|