File Coverage

blib/lib/Rapi/Blog/Util.pm
Criterion Covered Total %
statement 21 81 25.9
branch 0 48 0.0
condition 0 43 0.0
subroutine 7 19 36.8
pod 0 10 0.0
total 28 201 13.9


line stmt bran cond sub pod time code
1             package Rapi::Blog::Util;
2              
3 2     2   12 use strict;
  2         4  
  2         49  
4 2     2   10 use warnings;
  2         2  
  2         54  
5              
6 2     2   9 use RapidApp::Util ':all';
  2         4  
  2         705  
7              
8 2     2   2391 use DateTime;
  2         763604  
  2         84  
9 2     2   1037 use HTTP::Request::Common;
  2         3696  
  2         131  
10 2     2   1642 use LWP::UserAgent;
  2         38450  
  2         62  
11 2     2   803 use Rapi::Blog::Util::ppRender;
  2         6  
  2         1795  
12              
13             sub _dt_base_opts {(
14 0     0     time_zone => 'local'
15             )}
16              
17 0     0 0   sub now_ts { &dt_to_ts( &now_dt ) }
18 0     0 0   sub now_dt { DateTime->now( &_dt_base_opts ) }
19              
20             sub dt_to_ts {
21 0 0 0 0 0   shift if ($_[0] && $_[0] eq __PACKAGE__);
22 0           my $dt = shift;
23 0           join(' ',$dt->ymd('-'),$dt->hms(':'));
24             }
25              
26             # This is overkill and probably silly; I wrote it to be able to rule out possible time-zone
27             # inflate/deflate conversion issues. As a sanity check, I can always compare apples to
28             # apples with the DateTime/db-date-string conversion funcs in this package
29             sub ts_to_dt {
30 0 0 0 0 0   shift if ($_[0] && $_[0] eq __PACKAGE__);
31 0           my $ts = shift;
32 0 0         length($ts) == 19 or die "Bad timestamp '$ts' - should be exactly 19 characters long (YYYY-MM-DD hh:mm:ss)";
33            
34 0           my ($date,$time) = split(/\s/,$ts,2);
35 0 0         length($date) == 10 or die "Bad date part '$date' - should be exactly 10 characters long (YYYY-MM-DD)";
36 0 0         length($time) == 8 or die "Bad time part '$time' - should be exactly 8 characters long (hh:mm:ss)";
37            
38 0           my @d = split(/\-/,$date);
39 0           my @t = split(/\:/,$time);
40 0 0         scalar(@d) == 3 or die "Bad date part '$date' - didn't split ('-') into exactly 3 items";
41 0 0         scalar(@t) == 3 or die "Bad time part '$time' - didn't split (':') into exactly 3 items";
42            
43 0           my %o = ( &_dt_base_opts );
44 0           ($o{year},$o{month},$o{day},$o{hour},$o{minute},$o{second}) = (@d,@t);
45            
46 0           DateTime->new(%o)
47             }
48              
49             sub get_uid {
50 0 0   0 0   if(my $c = RapidApp->active_request_context) {
51 0 0 0       return $c->user->linkedRow->id if ($c->can('user') && $c->user && $c->user->linkedRow);
      0        
52             }
53 0           return 0;
54             }
55              
56             sub get_User {
57 0 0   0 0   if(my $c = RapidApp->active_request_context) {
58 0 0 0       return $c->user->linkedRow if ($c->can('user') && $c->user);
59             }
60 0           return undef;
61             }
62              
63              
64             sub get_scaffold_cfg {
65 0 0   0 0   if(my $c = RapidApp->active_request_context) {
66 0     0     return try{$c->template_controller->Access->scaffold_cfg};
  0            
67             }
68 0           return undef;
69             }
70              
71              
72             sub recaptcha_active {
73 0 0 0 0 0   shift if ($_[0] && $_[0] eq __PACKAGE__);
74 0 0 0       my $c = shift || RapidApp->active_request_context or return 0;
75            
76 0           my $cfg = $c->ra_builder->recaptcha_config;
77            
78             # When 'strict_mode' is active, we force recaptcha verification in all places it is supported
79             # (i.e. force ->opportunistic_recaptcha_verify to behave the same as ->recaptcha_verify)
80             # This prevents circumventing recaptcha validation by clients constructing their own POST request.
81             # The downside is that if front-side templates fail to properly enable the reCAPTCHA client side
82             # setup, the associated forms will always fail to submit because reCAPTCHA will always fail
83 0 0         return 1 if ($cfg->{strict_mode});
84              
85             $cfg->{public_key}
86             && $cfg->{private_key}
87             && $c->req->method eq 'POST'
88 0 0 0       && exists $c->req->params->{'g-recaptcha-response'}
      0        
89             }
90              
91             # opportunistic_recaptcha_verify only runs, and possibly fails, if all the needed reCAPTCHA pieces
92             # are active. When 'strict_mode' is turned on, this method behaves the same as recaptcha_verify.
93             # See the POD for more information of 'strict_mode'
94             sub opportunistic_recaptcha_verify {
95 0 0 0 0 0   shift if ($_[0] && $_[0] eq __PACKAGE__);
96 0 0 0       my $c = shift || RapidApp->active_request_context or return 1;
97 0 0         &recaptcha_active($c) ? &recaptcha_verify($c) : 1
98             }
99              
100              
101             sub recaptcha_verify {
102 0 0 0 0 0   shift if ($_[0] && $_[0] eq __PACKAGE__);
103 0   0       my $c = shift || RapidApp->active_request_context;
104            
105 0 0         &recaptcha_active($c) or return 0;
106            
107 0           my $cfg = $c->ra_builder->recaptcha_config;
108              
109             my $packet = {
110             secret => $cfg->{private_key},
111 0           response => $c->req->params->{'g-recaptcha-response'},
112             #remoteip => $c->req->address
113             };
114 0           my $content_payload = join('&',map { join('=',$_,$packet->{$_}) } keys %$packet);
  0            
115            
116 0   0       my $url = $cfg->{verify_url} || 'https://www.google.com/recaptcha/api/siteverify';
117            
118             # for refernece, this is how to turn of certificate validation, which should not be needed
119             # as long as the remote endpoint is a Google system
120             #local $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;
121            
122 0           my $ua = LWP::UserAgent->new;
123 0           $ua->agent('rapi-blog/' . $Rapi::Blog::VERSION);
124 0           $ua->timeout(30); # 30 seconds
125              
126 0           my $req = HTTP::Request->new( 'POST', $url );
127 0           $req->header( 'Content-Type' => 'application/x-www-form-urlencoded' );
128 0           $req->content( $content_payload );
129              
130 0           $c->log->info('Validating reCAPTCHA: POST -> '.$url);
131 0           my $res = $ua->request($req);
132              
133 0 0         if($res->is_success) {
134 0           my $data = decode_json_utf8( $res->decoded_content );
135              
136 0           my $success = $data->{success};
137 0 0 0       $success = $$success if (ref($success)||'' eq 'SCALAR');
138            
139 0 0         return $success ? 1 : 0
140             }
141             else {
142 0           $c->log->error('reCAPTCHA validation failed');
143 0           return 0;
144             }
145             }
146              
147              
148             1;