File Coverage

lib/CallBackery.pm
Criterion Covered Total %
statement 69 76 90.7
branch 8 18 44.4
condition 2 6 33.3
subroutine 15 17 88.2
pod 1 1 100.0
total 95 118 80.5


line stmt bran cond sub pod time code
1             package CallBackery;
2              
3              
4             =head1 NAME
5              
6             CallBackery - Appliance Frontend Builder
7              
8             =head1 SYNOPSIS
9              
10             require Mojolicious::Commands;
11             Mojolicious::Commands->start_app('CallBackery');
12              
13             =head1 DESCRIPTION
14              
15             Configure the mojo engine to run our application logic as webrequests arrive.
16              
17             =head1 ATTRIBUTES
18              
19             =cut
20              
21             # load the two modules to have perl check them
22             # having a non-C locale for number will wreck all sorts of havoc
23             # when things get converted to string and back
24 1     1   979 use POSIX qw(locale_h);
  1         2  
  1         53  
25             setlocale(LC_NUMERIC, "C");
26             setlocale(LC_TIME, "C");
27              
28 1     1   267 use Mojo::Base 'Mojolicious';
  1         3  
  1         20  
29 1     1   68493 use Mojolicious::Plugin::Qooxdoo;
  1         2751  
  1         23  
30 1     1   53 use Mojo::URL;
  1         2  
  1         17  
31 1     1   30 use Mojo::JSON;
  1         3  
  1         38  
32 1     1   6 use Mojo::Util qw(hmac_sha1_sum);
  1         7  
  1         44  
33 1     1   5 use Mojo::File qw(path);
  1         3  
  1         40  
34 1     1   7 use File::Basename;
  1         4  
  1         55  
35 1     1   715 use CallBackery::Config;
  1         3  
  1         18  
36 1     1   742 use CallBackery::Plugin::Doc;
  1         2  
  1         13  
37 1     1   568 use CallBackery::Database;
  1         3  
  1         19  
38 1     1   689 use CallBackery::User;
  1         4  
  1         10  
39              
40             our $VERSION = '0.47.3';
41              
42              
43             =head2 config
44              
45             A hash pointer to the configuration object. See L for details.
46             The default configuration file is located in etc/callbackery.cfg. You can override the
47             path by setting the C environment variable.
48              
49             The config property is set automatically on startup.
50              
51             =cut
52              
53             has 'config' => sub {
54             my $app = shift;
55             my $conf = CallBackery::Config->new(
56             app => $app,
57             file => $ENV{CALLBACKERY_CONF} || $app->home->child('etc','callbackery.cfg')
58             );
59             };
60              
61             =head2 database
62              
63             An instance of L or a module with the same API.
64              
65             =cut
66              
67             has 'database' => sub {
68             CallBackery::Database->new(app=>shift);
69             };
70              
71             has 'userObject' => sub {
72             CallBackery::User->new();
73             };
74              
75             =head2 securityHeaders
76              
77             A hash of headers to set on every response to ask the webbrowser to
78             help us fight the bad guys.
79              
80             =cut
81              
82             has securityHeaders => sub { {
83             # prevent click jacking
84             'X-Frame-Options' => 'SAMEORIGIN',
85             # some magic browser based anti xss action
86             'X-XSS-Protection' => '1; mode=block',
87             # the browser should obej the servers settings regarding content-type
88             'X-Content-Type-Options' => 'nosniff',
89             # do not store our data ever
90             'Pragma' => 'private',
91             }};
92              
93             =head2 rpcServiceNamespace
94              
95             our rpc service namespace
96              
97             =cut
98              
99             has rpcServiceNamespace => 'CallBackery';
100              
101             =head2 rpcServiceController
102              
103             our rpc service controller
104              
105             =cut
106              
107             has rpcServiceController => 'Controller::RpcService';
108              
109             =head2 docIndex
110              
111             initial document to be presented on the doc link
112              
113             =cut
114              
115             has docIndex => __PACKAGE__ . '::Index';
116              
117             =head1 METHODS
118              
119             All the methods of L as well as:
120              
121             =cut
122              
123             =head2 startup
124              
125             Mojolicious calls the startup method at initialization time.
126              
127             =cut
128              
129             sub startup {
130 1     1 1 29819 my $app = shift;
131             # having a non-C locale for number will wreck all sorts of havoc
132             # when things get converted to string and back
133 1         8 setlocale(LC_NUMERIC, "C");
134 1         3 setlocale(LC_TIME, "C");
135              
136 1         4 $app->config->postProcessCfg();
137 1         7 my $gcfg = $app->config->cfgHash->{BACKEND};
138 1 50       15 if ($gcfg->{log_file}){
139 0 0       0 if (open my $file, '>>', $gcfg->{log_file}){
140 0         0 $app->log->handle($file);
141             }
142             else {
143 0         0 $app->log->debug("Opening $gcfg->{log_file}: $!");
144             }
145             }
146              
147 1 50       8 unshift @{$app->static->paths},
  1         24  
148             $app->home->rel_file('frontend').'/compiled/source/'
149             if $app->mode eq 'development'; # Router
150              
151             # properly figure your own path when running under fastcgi
152             $app->hook( before_dispatch => sub {
153 4     4   44618 my $c = shift;
154 4         16 my $reqEnv = $c->req->env;
155 4   33     87 my $uri = $reqEnv->{SCRIPT_URI} || $reqEnv->{REQUEST_URI};
156 4         11 my $path_info = $reqEnv->{PATH_INFO};
157 4 50 33     15 $uri =~ s|/?${path_info}$|/| if $path_info and $uri;
158 4 50       11 $c->req->url->base(Mojo::URL->new($uri)) if $uri;
159 1         58 });
160              
161             $app->hook( after_dispatch => sub {
162 4     4   18556 my $c = shift;
163             # not telling anyone that we are mojo
164 4         14 $c->res->headers->remove('Server');
165 4 50       129 my $securityHeaders = $c->can('securityHeaders') ? $c->securityHeaders : $app->securityHeaders;
166 4         84 for my $header ( keys %$securityHeaders){
167 16         441 $c->res->headers->header($header,$securityHeaders->{$header});
168             }
169 4 50       140 $c->res->headers->cache_control('no-cache, no-store, must-revalidate')
170             unless $c->req->url->path =~ m{/resource/.+};
171 1         34 });
172            
173 1 50       12 if (my $secrets = $app->config->secretFile) {
174 1 50       23 if (-r $secrets) {
175 1         9 $app->secrets([ path($app->config->secretFile)->slurp ]);
176             }
177             else {
178 0         0 $app->log->error("Cannot read secrets file $secrets. Please check permissions.");
179             }
180             }
181            
182 1         230 my $routes = $app->routes;
183              
184             $app->plugin('CallBackery::Plugin::Doc', {
185             root => '/doc',
186             index => $app->docIndex,
187             template => Mojo::Asset::File->new(
188 1         12 path=>dirname($INC{'CallBackery/Config.pm'}).'/templates/doc.html.ep',
189             )->slurp,
190             });
191              
192 1         11 $routes->any('/upload')->to(namespace => $app->rpcServiceNamespace, controller=>$app->rpcServiceController, action => 'handleUpload');
193 1         428 $routes->any('/download')->to(namespace => $app->rpcServiceNamespace, controller=>$app->rpcServiceController, action => 'handleDownload');
194              
195             # this is a dummy login screen, we use inside an iframe to trick the browser
196             # into storing our password for auto-fill. Since there is no standard for triggering the
197             # behavior, this is all a bit voodoo, sorry. -- tobi
198             $routes->get('/login')->to(cb => sub {
199 0     0   0 my $c = shift;
200 0         0 $c->render(data=><'html');
201            
202            
203            
204            
205             HTML
206 1         345 });
207             # second stage of the deception. the answer page for login must not be the same as the original page
208             # otherwise the browser assumes the login failed and does not offer to save the password.
209             $routes->post('/login')->to(cb => sub {
210 0     0   0 shift->render(text=>'gugus :)');
211 1         326 });
212              
213              
214 1         305 $app->plugin('qooxdoo',{
215             path => '/QX-JSON-RPC',
216             namespace => $app->rpcServiceNamespace,
217             controller => $app->rpcServiceController,
218             });
219              
220              
221 1         700 return 0;
222             }
223              
224             1;
225              
226             __END__