File Coverage

blib/lib/Facebook/Signed.pm
Criterion Covered Total %
statement 3 5 60.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Facebook::Signed;
2             BEGIN {
3 1     1   51923 $Facebook::Signed::AUTHORITY = 'cpan:GETTY';
4             }
5             BEGIN {
6 1     1   20 $Facebook::Signed::VERSION = '0.102';
7             }
8             # ABSTRACT: Signed values given by Facebook to an application
9              
10 1     1   1815 use Moose;
  0            
  0            
11             use Digest::SHA qw/hmac_sha256/;
12             use Digest::MD5 qw/md5_hex/;
13             use MIME::Base64::URLSafe;
14             use JSON;
15             use Carp qw/croak/;
16             use namespace::autoclean;
17              
18              
19             has canvas_param => (
20             isa => 'Str',
21             is => 'ro',
22             required => 0,
23             );
24              
25              
26             has cookie_param => (
27             isa => 'Str',
28             is => 'ro',
29             required => 0,
30             );
31              
32              
33              
34             has secret => (
35             isa => 'Str',
36             is => 'ro',
37             lazy => 1,
38             default => sub { croak "secret required" },
39             );
40              
41             has _signed_values => (
42             isa => 'HashRef',
43             is => 'ro',
44             lazy => 1,
45             default => sub {
46             my ( $self ) = @_;
47              
48             if ($self->canvas_param and $self->cookie_param) {
49             croak "You must use one (and only one) of canvas_param OR cookie_param";
50             } elsif ($self->canvas_param) {
51             check_canvas_payload($self->canvas_param, $self->secret);
52             } elsif ($self->cookie_param) {
53             check_cookie_payload($self->cookie_param, $self->secret);
54             } else {
55             return {};
56             }
57             },
58             );
59              
60              
61             sub get {
62             my ( $self, $key ) = @_;
63             return $self->_signed_values->{$key};
64             }
65              
66              
67             sub check_canvas_payload {
68             my ( $facebook_data, $app_secret ) = @_;
69              
70             return {} if !$facebook_data;
71              
72             my ($encoded_sig, $payload) = split('\.', $facebook_data);
73             my $sig = urlsafe_b64decode($encoded_sig);
74             my $data = decode_json(urlsafe_b64decode($payload));
75             my $expected_sig = hmac_sha256($payload, $app_secret);
76              
77             if ($sig eq $expected_sig) {
78             return $data;
79             }
80              
81             return {};
82             }
83              
84              
85             sub check_cookie_payload {
86             my ( $facebook_data, $app_secret ) = @_;
87              
88             my $hash;
89             my $payload;
90              
91             map {
92             # TODO: test what happens if you have a = in the values
93             my ($k,$v) = split '=', $_;
94             $hash->{$k} = $v;
95             $payload .= $k .'='. $v if $k ne 'sig';
96             } split('&',$facebook_data);
97              
98             if (md5_hex($payload.$app_secret) eq $hash->{sig}) {
99             # TODO: fix html encoding?
100             return $hash;
101             }
102              
103             return {};
104             }
105              
106              
107             sub uid {
108             my ( $self ) = @_;
109             return $self->get('uid') ? $self->get('uid') : $self->get('user_id');
110             }
111              
112              
113             sub access_token {
114             my ( $self ) = @_;
115             return $self->get('access_token');
116             }
117              
118              
119             sub session_key {
120             my ( $self ) = @_;
121             return $self->get('session_key');
122             }
123              
124              
125             sub expires {
126             my ( $self ) = @_;
127             return $self->get('expires');
128             }
129              
130              
131             sub base_domain {
132             my ( $self ) = @_;
133             return $self->get('base_domain');
134             }
135              
136             1;
137              
138             __END__
139             =pod
140              
141             =head1 NAME
142              
143             Facebook::Signed - Signed values given by Facebook to an application
144              
145             =head1 VERSION
146              
147             version 0.102
148              
149             =head1 SYNOPSIS
150              
151             my $signed = Facebook::Signed->new(
152             cookie_param => $cookie_as_text,
153             secret => $secret,
154             );
155              
156             OR
157              
158             my $signed = Facebook::Signed->new(
159             canvas_param => $canvas_as_text,
160             secret => $secret,
161             );
162              
163             OR
164              
165             my $signed = Facebook::Signed->new(
166             secret => $secret,
167             );
168              
169             my $custom_value = $signed->get('custom_key');
170              
171             # shortcuts, return undef if not existing
172             my $fb_uid = $signed->uid;
173             my $fb_access_token = $signed->access_token;
174             my $fb_session_key = $signed->session_key;
175              
176             =head1 DESCRIPTION
177              
178             If you have any suggestion how we can use this package namespace, please suggest to authors listed in the end of this document.
179              
180             =head1 METHODS
181              
182             =head2 canvas_param
183              
184             Is a: String
185              
186             This data is used for getting the signed values. Either this parameter or
187             cookie_param (ONLY ONE) is required on construction.
188              
189             =head2 cookie_param
190              
191             Is a: String
192              
193             This data is used for getting the signed values. Either this parameter or
194             canvas_param (ONLY ONE) is required on construction.
195              
196             =head2 secret
197              
198             Is a: String
199              
200             This is the secret for your application. It's required on construction.
201              
202             =head2 $obj->get
203              
204             Arguments: $key
205              
206             Return value: Str
207              
208             Returns the value of a specific key of the signed values or undef it this is not exist.
209              
210             =head2 Facebook::Signed::check_canvas_payload
211              
212             Arguments: $facebook_data, $app_secret
213              
214             Return value: HashRef
215              
216             Checks the signature of the given facebook data from canvas with the given
217             application secret and gives back the checked HashRef or an empty one.
218              
219             =head2 Facebook::Signed::check_cookie_payload
220              
221             Arguments: $facebook_data, $app_secret
222              
223             Return value: HashRef
224              
225             Checks the signature of the given facebook data from a cookie with the
226             given application secret and gives back the checked HashRef or an empty
227             one.
228              
229             =head2 $obj->uid
230              
231             Arguments: None
232              
233             Return value: Integer
234              
235             Gives back the signed uid of the signed values given
236              
237             =head2 $obj->access_token
238              
239             Arguments: None
240              
241             Return value: String
242              
243             Gives back the signed access_token of the signed values given
244              
245             =head2 $obj->session_key
246              
247             Arguments: None
248              
249             Return value: String
250              
251             Gives back the signed session_key of the signed values given
252              
253             =head2 $obj->expires
254              
255             Arguments: None
256              
257             Return value: Integer
258              
259             Gives back the signed expire date as timestamp of the signed values given
260              
261             =head2 $obj->base_domain
262              
263             Arguments: None
264              
265             Return value: String
266              
267             Gives back the signed base_domain of the cookie given
268              
269             =encoding utf8
270              
271             =head1 ATTRIBUTES
272              
273             =head1 METHODS
274              
275             =head1 AUTHORS
276              
277             =over 4
278              
279             =item *
280              
281             Torsten Raudssus <torsten@raudssus.de> L<http://www.raudssus.de/>
282              
283             =item *
284              
285             Frank Sheiness <syndesis@gmail.com>
286              
287             =back
288              
289             =head1 COPYRIGHT AND LICENSE
290              
291             This software is copyright (c) 2011 by Raudssus Social Software & Facebook Distribution Authors.
292              
293             This is free software; you can redistribute it and/or modify it under
294             the same terms as the Perl 5 programming language system itself.
295              
296             =cut
297