line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
5
|
|
|
5
|
|
151892
|
use strict; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
186
|
|
2
|
5
|
|
|
5
|
|
25
|
use warnings; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
224
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package WebService::Freebox; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Freebox API wrappers. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
9
|
5
|
|
|
5
|
|
4340
|
use Mouse; |
|
5
|
|
|
|
|
222193
|
|
|
5
|
|
|
|
|
29
|
|
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
7430
|
use JSON; |
|
5
|
|
|
|
|
112938
|
|
|
5
|
|
|
|
|
42
|
|
12
|
5
|
|
|
5
|
|
8526
|
use REST::Client; |
|
5
|
|
|
|
|
340108
|
|
|
5
|
|
|
|
|
3688
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '0.001'; # VERSION |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has app_id => ( is => 'ro', isa => 'Str', required => 1 ); |
17
|
|
|
|
|
|
|
has app_version => ( is => 'ro', isa => 'Str', required => 1 ); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
has app_token => ( is => 'ro', isa => 'Str' ); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has _client => ( is => 'ro', builder => '_create_client' ); |
22
|
|
|
|
|
|
|
has _api_version => ( is => 'ro', builder => '_get_api_version' ); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Create the REST client we're going to use for all our requests. |
25
|
|
|
|
|
|
|
sub _create_client { |
26
|
0
|
|
|
0
|
|
|
my $self = shift; |
27
|
|
|
|
|
|
|
|
28
|
0
|
|
|
|
|
|
my $c = REST::Client->new(host => 'http://mafreebox.freebox.fr'); |
29
|
0
|
|
|
|
|
|
$c->addHeader('Accept', 'application/json'); |
30
|
0
|
|
|
|
|
|
$c->addHeader('Content-Type', 'application/json'); |
31
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
|
return $c; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Wrapper around REST::Client request() checking for errors: the first |
36
|
|
|
|
|
|
|
# argument is the error message given if the request failed. |
37
|
|
|
|
|
|
|
sub _request { |
38
|
0
|
|
|
0
|
|
|
my ($self, $errmsg, $request, $url, $body) = @_; |
39
|
|
|
|
|
|
|
|
40
|
0
|
|
|
|
|
|
my $c = $self->_client; |
41
|
0
|
|
|
|
|
|
$c->request($request, $url, $body); |
42
|
|
|
|
|
|
|
|
43
|
0
|
|
|
|
|
|
my $errcode = $c->responseCode(); |
44
|
0
|
0
|
|
|
|
|
if ($errcode != 200) { |
45
|
0
|
|
|
|
|
|
die qq{$errmsg ("$request $url" failed with HTTP error $errcode).\n} |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
return decode_json $c->responseContent() |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Helper for making normal API requests, i.e. all except for the initial one, |
52
|
|
|
|
|
|
|
# checking for the Freebox presence and detecting the API version. |
53
|
|
|
|
|
|
|
sub _api_request { |
54
|
0
|
|
|
0
|
|
|
my ($self, $errmsg, $request, $url, @rest) = @_; |
55
|
0
|
|
|
|
|
|
$self->_request($errmsg, $request, '/api/v' . $self->_api_version . "/$url", @rest); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# Detect the Freebox and get the API version used by it. |
59
|
|
|
|
|
|
|
sub _get_api_version { |
60
|
0
|
|
|
0
|
|
|
my $self = shift; |
61
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
|
my $res = $self->_request('Freebox v6 not detected', 'GET', '/api_version'); |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
my $api_version = $res->{api_version}; |
65
|
0
|
0
|
|
|
|
|
die "Unexpected Freebox API version $api_version.\n" if $api_version !~ '[23].0'; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# We need to use just the major number in the HTTP requests. |
68
|
0
|
|
|
|
|
|
$api_version =~ s/\.\d$//; |
69
|
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
return $api_version; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub authorize { |
78
|
0
|
|
|
0
|
1
|
|
my ($self, $app_name, $device_name) = @_; |
79
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
my $app_id = $self->app_id; |
81
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
my $res = $self->_api_request( |
83
|
|
|
|
|
|
|
'Requesting authorization failed', |
84
|
|
|
|
|
|
|
'POST', |
85
|
|
|
|
|
|
|
'login/authorize/', |
86
|
|
|
|
|
|
|
encode_json({ |
87
|
|
|
|
|
|
|
app_id => $app_id, |
88
|
|
|
|
|
|
|
app_name => $app_name, |
89
|
|
|
|
|
|
|
app_version => $self->app_version, |
90
|
|
|
|
|
|
|
device_name => $device_name |
91
|
|
|
|
|
|
|
}) |
92
|
|
|
|
|
|
|
); |
93
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my $app_token = $res->{result}{app_token}; |
95
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
my $track_id = $res->{result}{track_id}; |
97
|
0
|
|
|
|
|
|
while (1) { |
98
|
0
|
|
|
|
|
|
$res = $self->_api_request( |
99
|
|
|
|
|
|
|
'Waiting for authorization failed', |
100
|
|
|
|
|
|
|
'GET', |
101
|
|
|
|
|
|
|
"login/authorize/$track_id" |
102
|
|
|
|
|
|
|
); |
103
|
|
|
|
|
|
|
|
104
|
0
|
0
|
|
|
|
|
last if $res->{result}{status} ne 'pending'; |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
sleep 1; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
0
|
0
|
|
|
|
|
die "Failed to obtain authorization for $app_id: $res->{result}{status}.\n" |
110
|
|
|
|
|
|
|
unless $res->{result}{status} eq 'granted'; |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
return $app_token |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub login { |
118
|
0
|
|
|
0
|
1
|
|
my ($self, $session_token) = @_; |
119
|
|
|
|
|
|
|
|
120
|
0
|
0
|
|
|
|
|
if (defined $session_token) { |
121
|
0
|
|
|
|
|
|
$self->_client->addHeader('X-Fbx-App-Auth', $session_token); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
my $res = $self->_api_request( |
125
|
|
|
|
|
|
|
'Checking logged in status failed', |
126
|
|
|
|
|
|
|
'GET', |
127
|
|
|
|
|
|
|
'login/' |
128
|
|
|
|
|
|
|
); |
129
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
|
if (!$res->{result}{logged_in}) { |
131
|
5
|
|
|
5
|
|
6266
|
use Digest::SHA qw(hmac_sha1_hex); |
|
5
|
|
|
|
|
22321
|
|
|
5
|
|
|
|
|
2156
|
|
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
my $challenge = $res->{result}{challenge}; |
134
|
0
|
|
|
|
|
|
my $password = hmac_sha1_hex($challenge, $self->app_token); |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
$res = $self->_api_request( |
137
|
|
|
|
|
|
|
'Logging in failed', |
138
|
|
|
|
|
|
|
'POST', |
139
|
|
|
|
|
|
|
"login/session/", |
140
|
|
|
|
|
|
|
encode_json({ |
141
|
|
|
|
|
|
|
app_id => $self->app_id, |
142
|
|
|
|
|
|
|
app_version => $self->app_version, |
143
|
|
|
|
|
|
|
password => $password, |
144
|
|
|
|
|
|
|
}) |
145
|
|
|
|
|
|
|
); |
146
|
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
|
$session_token = $res->{result}{session_token}; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
$self->_client->addHeader('X-Fbx-App-Auth', $session_token); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
return $session_token; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub get_system_config { |
158
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
159
|
|
|
|
|
|
|
|
160
|
0
|
|
|
|
|
|
my $res = $self->_api_request( |
161
|
|
|
|
|
|
|
'Getting system configuration failed', |
162
|
|
|
|
|
|
|
'GET', |
163
|
|
|
|
|
|
|
'system/' |
164
|
|
|
|
|
|
|
); |
165
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
return $res->{result} |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub get_connection_status { |
172
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
my $res = $self->_api_request( |
175
|
|
|
|
|
|
|
'Getting connection status failed', |
176
|
|
|
|
|
|
|
'GET', |
177
|
|
|
|
|
|
|
'connection/' |
178
|
|
|
|
|
|
|
); |
179
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
|
return $res->{result} |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub get_all_freeplugs { |
186
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my $res = $self->_api_request( |
189
|
|
|
|
|
|
|
'Failed to get freeplugs list', |
190
|
|
|
|
|
|
|
'GET', |
191
|
|
|
|
|
|
|
'freeplug/' |
192
|
|
|
|
|
|
|
); |
193
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
my $fps = []; |
195
|
0
|
|
|
|
|
|
foreach my $fp (@{$res->{result}[0]{members}}) { |
|
0
|
|
|
|
|
|
|
196
|
0
|
|
|
|
|
|
push @$fps, $fp; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
|
return $fps |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
__END__ |