rvd_front.pl 68.6 KB
Newer Older
1
2
3
#!/usr/bin/env perl
use warnings;
use strict;
4
5
6
#####
use locale ':not_characters';
#####
Francesc Guasch's avatar
Francesc Guasch committed
7
8
9
use lib 'lib';

use Carp qw(confess cluck);
10
use Data::Dumper;
11
use Digest::SHA qw(sha256_hex);
12
use Hash::Util qw(lock_hash);
13
use Mojolicious::Lite 'Ravada::I18N';
Francesc Guasch's avatar
Francesc Guasch committed
14
use Mojo::JSON qw(decode_json encode_json);
15
use Time::Piece;
16
#use Mojolicious::Plugin::I18N;
17
use Mojo::Home;
Francesc Guasch's avatar
Francesc Guasch committed
18
19

use I18N::LangTags::Detect;
20
#####
21
22
#my $self->plugin('I18N');
#package Ravada::I18N:en;
23
#####
24
25
26
#
no warnings "experimental::signatures";
use feature qw(signatures);
27

28

29
use Ravada::Front;
30
use Ravada::Front::Domain;
Francesc Guasch's avatar
Francesc Guasch committed
31
use Ravada::Auth;
Francesc Guasch's avatar
Francesc Guasch committed
32
use Ravada::WebSocket;
33
use POSIX qw(locale_h);
Francesc Guasch's avatar
Francesc Guasch committed
34
35

my $help;
Francesc Guasch's avatar
Francesc Guasch committed
36

Francesc Guasch's avatar
Francesc Guasch committed
37
38
39
my $FILE_CONFIG = "/etc/rvd_front.conf";

my $error_file_duplicated = 0;
40
for my $file ( "/etc/rvd_front.conf" , ($ENV{HOME} or '')."/rvd_front.conf") {
Francesc Guasch's avatar
Francesc Guasch committed
41
    warn "WARNING: Found config file at $file and at $FILE_CONFIG\n"
42
        if -e $file && $FILE_CONFIG && $file ne $FILE_CONFIG;
43
    $FILE_CONFIG = $file if -e $file;
Francesc Guasch's avatar
Francesc Guasch committed
44
    $error_file_duplicated++;
45
}
Francesc Guasch's avatar
Francesc Guasch committed
46
warn "WARNING: using $FILE_CONFIG\n"    if$error_file_duplicated>2;
47
48

my $FILE_CONFIG_RAVADA;
49
for my $file ( "/etc/ravada.conf" , ($ENV{HOME} or '')."/ravada.conf") {
50
51
52
    warn "WARNING: Found config file at $file and at $FILE_CONFIG_RAVADA\n"
        if -e $file && $FILE_CONFIG_RAVADA;
    $FILE_CONFIG_RAVADA = $file if -e $file;
Francesc Guasch's avatar
Francesc Guasch committed
53
}
54

amesones's avatar
amesones committed
55
56
57
my $CONFIG_FRONT = plugin Config => { default => {
                                                hypnotoad => {
                                                pid_file => 'log/rvd_front.pid'
fv3rdugo's avatar
Indent    
fv3rdugo committed
58
59
                                                ,listen => ['http://*:8081']
                                                }
60
                                              ,login_bg_file => '/img/intro-bg.jpg'
Francesc Guasch's avatar
Francesc Guasch committed
61
                                              ,login_header => 'Welcome'
62
                                              ,login_message => ''
63
                                              ,secrets => ['changeme0']
64
                                              ,guide => 0
fv3rdugo's avatar
fv3rdugo committed
65
                                              ,login_custom => ''
66
                                              ,footer => 'bootstrap/footer'
67
                                              ,monitoring => 0
68
                                              ,fallback => 0
69
                                              ,guide_custom => ''
70
71
                                              ,admin => {
                                                    hide_clones => 15
Francesc Guasch's avatar
Francesc Guasch committed
72
                                                    ,autostart => 0
amesones's avatar
amesones committed
73
                                              }
74
                                              ,config => $FILE_CONFIG_RAVADA
75
                                              ,auto_view => 0
amesones's avatar
amesones committed
76
                                              }
Francesc Guasch's avatar
Francesc Guasch committed
77
                                      ,file => $FILE_CONFIG
78
};
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#####
#####
#####
# Import locale-handling tool set from POSIX module.
# This example uses: setlocale -- the function call
#                    LC_CTYPE -- explained below

# query and save the old locale
my $old_locale = setlocale(LC_CTYPE);

setlocale(LC_CTYPE, "en_US.ISO8859-1");
# LC_CTYPE now in locale "English, US, codeset ISO 8859-1"

setlocale(LC_CTYPE, "");
# LC_CTYPE now reset to default defined by LC_ALL/LC_CTYPE/LANG
# environment variables.  See below for documentation.

# restore the old locale
setlocale(LC_CTYPE, $old_locale);
#####
#####
#####
102
plugin I18N => {namespace => 'Ravada::I18N', default => 'en'};
Francesc Guasch's avatar
Francesc Guasch committed
103
plugin 'RenderFile';
Francesc Guasch's avatar
Francesc Guasch committed
104

105
my %config;
106
%config = (config => $CONFIG_FRONT->{config}) if $CONFIG_FRONT->{config};
107
our $RAVADA = Ravada::Front->new(%config);
108

109
our $USER;
Francesc Guasch's avatar
Francesc Guasch committed
110

111
# TODO: get those from the config file
112
our $DOCUMENT_ROOT = "/var/www";
113
114

# session times out in 5 minutes
115
our $SESSION_TIMEOUT = ($CONFIG_FRONT->{session_timeout} or 5 * 60);
116
# session times out in 15 minutes for admin users
117
our $SESSION_TIMEOUT_ADMIN = ($CONFIG_FRONT->{session_timeout_admin} or 15 * 60);
118

Francesc Guasch's avatar
Francesc Guasch committed
119
my $WS = Ravada::WebSocket->new(ravada => $RAVADA);
Francesc Guasch's avatar
Francesc Guasch committed
120
121
my %ALLOWED_ANONYMOUS_WS = map { $_ => 1 } qw(list_bases_anonymous list_alerts);

Francesc Guasch's avatar
Francesc Guasch committed
122
123
init();
############################################################################3
124

125
126
127
hook before_routes => sub {
  my $c = shift;

128
129
  $USER = undef;

Francesc Guasch's avatar
Francesc Guasch committed
130
  $c->stash(version => $RAVADA->version);
131
  my $url = $c->req->url->to_abs->path;
fv3rdugo's avatar
fv3rdugo committed
132
  my $host = $c->req->url->to_abs->host;
133
  $c->stash(css=>['/css/sb-admin.css']
Francesc Guasch's avatar
Francesc Guasch committed
134
135
            ,js=>[
                '/js/ravada.js'
136
137
138
                ]
            ,csssnippets => []
            ,navbar_custom => 0
Francesc Guasch's avatar
Francesc Guasch committed
139
140
141
142
            ,url => undef
            ,_logged_in => undef
            ,_anonymous => undef
            ,_user => undef
143
            ,footer=> $CONFIG_FRONT->{footer}
144
            ,monitoring => 0
fv3rdugo's avatar
fv3rdugo committed
145
            ,fallback => $CONFIG_FRONT->{fallback}
146
            ,check_netdata => 0
147
            ,guide => $CONFIG_FRONT->{guide}
fv3rdugo's avatar
fv3rdugo committed
148
            ,host => $host
149
            );
150

Francesc Guasch's avatar
Francesc Guasch committed
151
152
    return if _logged_in($c);
    return if $url =~ m{^/(anonymous|login|logout|requirements|robots.txt)}
Francesc Guasch's avatar
Francesc Guasch committed
153
154
           || $url =~ m{^/(css|font|img|js)}
	   || $url =~ m{^/fallback/.*\.(css|js|map)$};
155

Francesc Guasch's avatar
Francesc Guasch committed
156
157
158
    # anonymous URLs
    if (($url =~ m{^/machine/(clone|display|info|view)/}
        || $url =~ m{^/(list_bases_anonymous|request/)}i
Francesc Guasch's avatar
Francesc Guasch committed
159
        || $url =~ m{^/ws/subscribe}
Francesc Guasch's avatar
Francesc Guasch committed
160
161
162
163
164
165
        ) && !_logged_in($c)) {
        $USER = _anonymous_user($c);
        return if $USER->is_temporary;
    }
    return access_denied($c)
        if $url =~ /(screenshot|\.json)/
166
        && !_logged_in($c);
Francesc Guasch's avatar
Francesc Guasch committed
167
    return login($c) if !_logged_in($c);
168

169
170
171
172
173
174
    if ($USER && $USER->is_admin && $CONFIG_FRONT->{monitoring}) {
        if (!defined $c->session('monitoring')) {
            $c->stash(check_netdata => "https://$host:19999/index.html");
        }
        $c->stash( monitoring => 1) if $c->session('monitoring');
    }
175
        $c->stash( fallback => 1) if $c->session('fallback');
176
177
178
179
180
};


############################################################################3

Francesc Guasch's avatar
Francesc Guasch committed
181
182
183
184
185
any '/robots.txt' => sub {
    my $c = shift;
    return $c->render(text => "User-agent: *\nDisallow: /\n", format => 'text');
};

186
any '/' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
187
    my $c = shift;
188
    return quick_start($c);
Francesc Guasch's avatar
Francesc Guasch committed
189
190
};

Francesc Guasch's avatar
Francesc Guasch committed
191
192
any '/index.html' => sub {
    my $c = shift;
193
    return quick_start($c);
Francesc Guasch's avatar
Francesc Guasch committed
194
195
};

196
197
any '/login' => sub {
    my $c = shift;
198
    return login($c);
199
200
};

Francesc Guasch's avatar
Francesc Guasch committed
201
202
203
204
205
206
207
208
209
any '/test' => sub {
    my $c = shift;
    my $logged = _logged_in($c);
    my $count = $c->session('count');
    $c->session(count => ++$count);

    my $name_mojo = $c->signed_cookie('mojolicious');

    my $dump_log = ''.(Dumper($logged) or '');
Francesc Guasch's avatar
Francesc Guasch committed
210
211
212
213
214
    return $c->render(text => "$count ".($name_mojo or '')."<br> ".$dump_log
        ."<br>"
        ."<script>alert(window.screen.availWidth"
        ."+\" \"+window.screen.availHeight)</script>"
    );
Francesc Guasch's avatar
Francesc Guasch committed
215
216
};

Francesc Guasch's avatar
Francesc Guasch committed
217
218
any '/logout' => sub {
    my $c = shift;
219
    logout($c);
Francesc Guasch's avatar
Francesc Guasch committed
220
221
222
    $c->redirect_to('/');
};

223
get '/anonymous' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
224
    my $c = shift;
225
#    $c->render(template => 'bases', base => list_bases());
226
    $USER = _anonymous_user($c);
227
    return list_bases_anonymous($c);
Francesc Guasch's avatar
Francesc Guasch committed
228
229
};

230
get '/anonymous_logout.html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
231
    my $c = shift;
232
233
    $c->session('anonymous_user' => '');
    return $c->redirect_to('/');
Francesc Guasch's avatar
Francesc Guasch committed
234
235
};

236
get '/anonymous/(#base_id).html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
237
238
    my $c = shift;

239
    $c->stash(_anonymous => 1 , _logged_in => 0);
240
    _init_error($c);
241
    my $base_id = $c->stash('base_id');
242
243
    my $base = $RAVADA->search_domain_by_id($base_id);

244
    $USER = _anonymous_user($c);
245
    return quick_start_domain($c,$base->id, $USER->name);
Francesc Guasch's avatar
Francesc Guasch committed
246
247
};

248
any '/admin/#type' => sub {
249
  my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
250

251
252
253
  return admin($c)  if $c->stash('type') eq 'machines'
                        && $USER->is_operator;

254
255
  return access_denied($c)    if !$USER->is_operator;

amesones's avatar
amesones committed
256
  return admin($c);
Francesc Guasch's avatar
Francesc Guasch committed
257
258
};

259
any '/new_machine' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
260
    my $c = shift;
261
    return access_denied($c)    if !$USER->can_create_machine;
262
    return new_machine($c);
Francesc Guasch's avatar
Francesc Guasch committed
263
264
};

265
266
267
268
269
any '/copy_machine' => sub {
    my $c = shift;
    return new_machine_copy($c);
};

270
get '/domain/new.html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
271
272
    my $c = shift;

273
274
    return access_denied($c) if !_logged_in($c) || !$USER->is_admin();
    $c->stash(error => []);
amesones's avatar
amesones committed
275
    return $c->render(template => "main/new_machine");
Francesc Guasch's avatar
Francesc Guasch committed
276
277
278

};

279
280
get '/list_vm_types.json' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
281
    $c->render(json => $RAVADA->list_vm_types);
282
283
};

284
285
286
287
288
289
290
291
292
293
294
295
296
297
get '/list_nodes.json' => sub {
    my $c = shift;
    $c->render(json => [$RAVADA->list_vms]);
};

get '/node/enable/(:id).json' => sub {
    my $c = shift;
    return access_denied($c) if !$USER->is_admin;
    return $c->render(json => {enabled => $RAVADA->enable_node($c->stash('id'),1)});
};

get '/node/disable/(:id).json' => sub {
    my $c = shift;
    return access_denied($c) if !$USER->is_admin;
298
299
300
301
302

    my $machines = $RAVADA->_list_machines_vm($c->stash('id'));
    for ( @$machines ) {
        my $req = Ravada::Request->shutdown_domain( uid => $USER->id , id_domain => $_->{id} );
    }
303
304
    return $c->render(json => {enabled => $RAVADA->enable_node($c->stash('id'),0)});
};
305
306
307
308
309
get '/node/remove/(:id).json' => sub {
    my $c = shift;
    return access_denied($c) if !$USER->is_admin;
    return $c->render(json => {remove => $RAVADA->remove_node($c->stash('id'),1)});
};
310

Francesc Guasch's avatar
Francesc Guasch committed
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
get '/node/shutdown/(:id).json' => sub {
    my $c = shift;
    return access_denied($c) if !$USER->is_admin;

    my $machines = $RAVADA->_list_machines_vm($c->stash('id'));
    for ( @$machines ) {
        my $req = Ravada::Request->shutdown_domain(
                    uid => $USER->id
            , id_domain => $_->{id}
        );
    }
    my $at = 0;
    if (@$machines) {
        $at = time + 60 + scalar @$machines;
    }
    my $req = Ravada::Request->shutdown_node(
                id_node => $c->stash('id')
                ,at => $at
    );
    Ravada::Request->connect_node(
                id_node => $c->stash('id')
                ,at => $at + 10
    );
    return $c->render(json => {id_req => $req->id });
};

get '/node/start/(:id).json' => sub {
    my $c = shift;
    return access_denied($c) if !$USER->is_admin;
    my $req = Ravada::Request->start_node(
                id_node => $c->stash('id')
    );
    for my $seconds ( 30,60,90,120 ) {
        Ravada::Request->connect_node(
            id_node => $c->stash('id')
            ,at => time + $seconds
        );
    }

    return $c->render(json => {id_req => $req->id });

};

354
355
356
357
358
359
any '/new_node' => sub {
    my $c = shift;
    return access_denied($c)    if !$USER->is_admin;
    return new_node($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
get '/node/connect/(#backend)/(#hostname)' => sub {
    my $c = shift;
    return access_denied($c)    if !$USER->is_admin;
    my $req = Ravada::Request->connect_node(
                backend => $c->stash('backend')
                    ,hostname => $c->stash('hostname')
    );
    return $c->render(json => {id_req => $req->id });
};

get '/node/connect/(#id)' => sub {
    my $c = shift;
    return access_denied($c)    if !$USER->is_admin;
    my $req = Ravada::Request->connect_node(
        id_node => $c->stash('id')
    );
    return $c->render(json => {id_req => $req->id });
};


380
381
get '/list_bases.json' => sub {
    my $c = shift;
382
383
384
385
386
387
388
389
390
391
392

    my $domains = $RAVADA->list_bases();
    my @domains_show = @$domains;
    if (!$USER->is_admin) {
        @domains_show = ();
        for (@$domains) {
            push @domains_show,($_) if $_->{is_public};
        }
    }
    $c->render(json => [@domains_show]);

393
394
395
396
};

get '/list_images.json' => sub {
    my $c = shift;
397

elodin1's avatar
elodin1 committed
398
399
400
    return access_denied($c) unless _logged_in($c)
        && $USER->can_create_machine();

401
402
403
    my $vm_name = $c->param('backend');

    $c->render(json => $RAVADA->list_iso_images($vm_name or undef));
404
405
};

406
get '/iso_file.json' => sub {
joelalju's avatar
joelalju committed
407
    my $c = shift;
elodin1's avatar
elodin1 committed
408
409
    return access_denied($c) unless _logged_in($c)
        && $USER->can_create_machine();
410
    my @isos =('<NONE>');
Fernando Verdugo's avatar
Fernando Verdugo committed
411
    push @isos,(@{$RAVADA->iso_file('KVM')});
412
    $c->render(json => \@isos);
joelalju's avatar
joelalju committed
413
414
};

415
get '/list_machines.json' => sub {
416
    my $c = shift;
417

418
    return access_denied($c) unless _logged_in($c)
419
420
421
422
423
        && (
            $USER->can_list_machines
            || $USER->can_list_own_machines()
            || $USER->can_list_clones()
            || $USER->can_list_clones_from_own_base()
424
425
426
            || $USER->is_admin()
        );

427
    return $c->render( json => $RAVADA->list_machines($USER) );
428

429
};
Francesc Guasch's avatar
Francesc Guasch committed
430

431
432
433
get '/list_machines_user.json' => sub {
    my $c = shift;
    return $c->render( json => $RAVADA->list_machines_user($USER));
434
};
Francesc Guasch's avatar
Francesc Guasch committed
435

436
437
438
439
440
441
442
get '/list_bases_anonymous.json' => sub {
    my $c = shift;

    # shouldn't this be "list_bases" ?
    $c->render(json => $RAVADA->list_bases_anonymous(_remote_ip($c)));
};

Francesc Guasch's avatar
Francesc Guasch committed
443
get '/list_lxc_templates.json' => sub {
fv3rdugo's avatar
fv3rdugo committed
444
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
445
    $c->render(json => $RAVADA->list_lxc_templates);
fv3rdugo's avatar
fv3rdugo committed
446
447
};

448
449
# machine commands

450
get '/machine/info/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
451
    my $c = shift;
452
    my $id = $c->stash('id');
Francesc Guasch's avatar
Francesc Guasch committed
453
    die "No id " if !$id;
454

joelalju's avatar
joelalju committed
455
456
457
    my ($domain) = _search_requested_machine($c);
    return access_denied($c)    if !$domain;

458
    return access_denied($c,"Access denied to user ".$USER->name) unless $USER->can_manage_machine($domain->id);
Francesc Guasch's avatar
Francesc Guasch committed
459

460
461
    my $info = $domain->info($USER);
    if ($domain->is_active && !$info->{ip}) {
Francesc Guasch's avatar
Francesc Guasch committed
462
        Ravada::Request->refresh_machine(id_domain => $domain->id, uid => $USER->id);
463
464
    }
    return $c->render(json => $info);
Francesc Guasch's avatar
Francesc Guasch committed
465
466
};

Francesc Guasch's avatar
Francesc Guasch committed
467
get '/machine/requests/(:id).json' => sub {
468
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
469
    my $id_domain = $c->stash('id');
470
    return access_denied($c) unless $USER->can_manage_machine($id_domain);
joelalju's avatar
joelalju committed
471

Francesc Guasch's avatar
Francesc Guasch committed
472
473
    $c->render(json => $RAVADA->list_requests($id_domain,10));
};
joelalju's avatar
joelalju committed
474

475
any '/machine/manage/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
476
   	 my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
477
     Ravada::Request->refresh_machine(id_domain => $c->stash('id'), uid => $USER->id);
Francesc Guasch's avatar
Francesc Guasch committed
478
     return manage_machine($c);
479
};
joelalju's avatar
joelalju committed
480

Francesc Guasch's avatar
Francesc Guasch committed
481
482
483
any '/hardware/(:id).(:type)' => sub {
   	 my $c = shift;
     return $c->render(template => 'main/hardware');
484
485
};

486
get '/machine/view/(:id).(:type)' => sub {
487
    my $c = shift;
488
489
    my $id = $c->stash('id');
    my $type = $c->stash('type');
Francesc Guasch's avatar
Francesc Guasch committed
490

joelalju's avatar
joelalju committed
491
492
493
494
495
496
    my ($domain) = _search_requested_machine($c);
    return access_denied($c)    if !$domain;

    return access_denied($c) unless $USER->is_admin
                              || $domain->id_owner == $USER->id;

497
498
499
    return view_machine($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
500
any '/machine/clone/(:id).(:type)' => sub {
Joel Alarcón's avatar
Joel Alarcón committed
501
    my $c = shift;
502

Francesc Guasch's avatar
Francesc Guasch committed
503
504
505
506
507
508
509
510
511
512
513
    return clone_machine($c)    if $USER && $USER->can_clone() && !$USER->is_temporary();

    my $bases_anonymous = $RAVADA->list_bases_anonymous(_remote_ip($c));
    for (@$bases_anonymous) {
        if ($_->{id} == $c->stash('id') ) {
            return clone_machine($c,1);
        }
    }

    return login($c)    if !$USER || $USER->is_temporary;
    return access_denied($c);
514
};
Francesc Guasch's avatar
Francesc Guasch committed
515

516
get '/machine/shutdown/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
517
        my $c = shift;
518
    return access_denied($c)        if !$USER ->can_shutdown($c->stash('id'));
Francesc Guasch's avatar
Francesc Guasch committed
519
520
521
522

        return shutdown_machine($c);
};

523
any '/machine/remove/(:id).(:type)' => sub {
joansp's avatar
joansp committed
524
        my $c = shift;
525
    return access_denied($c)       if !$USER->can_remove_machine($c->stash('id'));
joansp's avatar
joansp committed
526
527
        return remove_machine($c);
};
528
529

any '/machine/remove_clones/(:id).(:type)' => sub {
530
531
532
533
534
535
    my $c = shift;

    # TODO : call to $domain->_allow_remove();
	return access_denied($c)
        unless
            $USER -> can_remove_clone_all()
Francesc Guasch's avatar
Francesc Guasch committed
536
537
	        || $USER->can_remove_clone()
            || $USER->can_remove_all();
538
    return remove_clones($c);
539
540
};

541
get '/machine/prepare/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
542
543
544
545
        my $c = shift;
        return prepare_machine($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
546
get '/machine/set_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
547
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
548
549
550
551
552
553
    return set_base_vm($c, 1);
};

get '/machine/remove_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
    my $c = shift;
    return set_base_vm($c, 0);
554
555
};

556
get '/machine/remove_b/(:id).(:type)' => sub {
joansp's avatar
joansp committed
557
558
559
560
        my $c = shift;
        return remove_base($c);
};

561
get '/machine/remove_base/(:id).(:type)' => sub {
562
563
564
565
    my $c = shift;
    return remove_base($c);
};

566
get '/machine/screenshot/(:id).(:type)' => sub {
567
        my $c = shift;
568
569
        my $domain = _search_requested_machine($c);
        return access_denied($c)   if (!$USER->can_screenshot() || $domain->is_base());
570
571
572
        return screenshot_machine($c);
};

573
get '/machine/copy_screenshot/(:id).(:type)' => sub {
574
575
576
        my $c = shift; 
        my $domain = _search_requested_machine($c);
        return access_denied($c) if (!$USER->is_admin() || $domain->id_base() == NULL );
577
578
579
        return copy_screenshot($c);
};

580
get '/machine/pause/(:id).(:type)' => sub {
joansp's avatar
joansp committed
581
582
583
584
        my $c = shift;
        return pause_machine($c);
};

585
get '/machine/hibernate/(:id).(:type)' => sub {
586
        my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
587
          return access_denied($c)
Francesc Guasch's avatar
Francesc Guasch committed
588
             unless $USER->is_admin() || $USER->can_shutdown($c->stash('id'));
Francesc Guasch's avatar
Francesc Guasch committed
589

590
591
592
        return hybernate_machine($c);
};

593
get '/machine/resume/(:id).(:type)' => sub {
joansp's avatar
joansp committed
594
595
596
597
        my $c = shift;
        return resume_machine($c);
};

598
get '/machine/start/(:id).(:type)' => sub {
joansp's avatar
joansp committed
599
600
601
        my $c = shift;
        return start_machine($c);
};
joansp's avatar
joansp committed
602

603
get '/machine/exists/#name' => sub {
604
    my $c = shift;
605
    my $name = $c->stash('name');
606
607
608
609
610
611
    #TODO
    # return failure if it can't find the name in the URL

    return $c->render(json => $RAVADA->domain_exists($name));

};
joansp's avatar
joansp committed
612

Francesc Guasch's avatar
Francesc Guasch committed
613
post '/machine/hardware/change' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
614
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
615
616
617
618
619
620
621
622
623
624
625
626
    my $arg = decode_json($c->req->body);

    my $domain = Ravada::Front::Domain->open(delete $arg->{id_domain});

    return access_denied($c)
        unless $USER->id == $domain->id_owner || $USER->is_admin;

    my $hardware = delete $arg->{hardware} or die "Missing hardware name";
    my $index = delete $arg->{index};
    my $data = delete $arg->{data};

    die "Unknown fields in request ".Dumper($arg) if keys %{$arg};
Francesc Guasch's avatar
Francesc Guasch committed
627
    return $c->render(json => { req => Ravada::Request->change_hardware(
Francesc Guasch's avatar
Francesc Guasch committed
628
629
630
631
                id_domain => $domain->id
                ,hardware => $hardware
                ,index => $index
                ,data => $data
Francesc Guasch's avatar
Francesc Guasch committed
632
633
634
635
636
                ,uid => $USER->id
            )
    });
};

Francesc Guasch's avatar
Francesc Guasch committed
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
get '/machine/list_access/(#id_domain)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    my @access0 = $domain->list_access();
    my $default = {};
    my @access;
    for my $access (@access0) {
        if ($access->{value} eq '*') {
            $default = $access;
            next;
        }
        push @access,($access);
    }

    return $c->render(json => {list => \@access, default => $default} );
};

get '/machine/check_access/(#id_domain)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    my %client;
    for my $name (@{$c->req->headers->names}) {
        $client{$name}= $c->req->headers->header($name);
    }
    return $c->render( json => { ok => $domain->access_allowed(client => \%client)});
};

get '/machine/delete_access/(#id_domain)/(#id_access)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);
    $domain->delete_access($c->stash('id_access'));

    # delete default if it is the only one left
    my @access = $domain->list_access();
    if (scalar @access == 1 && $access[0]->{value} eq '*') {
        $domain->delete_access($access[0]->{id});
    }

    return $c->render(json => { ok => 1 });

};

get '/machine/move_access/(#id_domain)/(#id_access)/(#position)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    $domain->move_access($c->stash('id_access'),$c->stash('position'));

    return $c->render(json => { ok => 1 });

};

707
708
709
710
711
712
713
get '/node/exists/#name' => sub {
    my $c = shift;
    my $name = $c->stash('name');

    return $c->render(json => $RAVADA->node_exists($name));

};
714
get '/machine/rename/#id/#value' => sub {
715
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
716
    return access_denied($c)       if !$USER->can_manage_machine($c->stash('id'));
717
718
719
    return rename_machine($c);
};

720
721
any '/machine/copy' => sub {
    my $c = shift;
722
    return access_denied($c)    if !$USER -> can_clone_all();
723
724
725
    return copy_machine($c);
};

726
727
728
729
730
731
get '/machine/public/#id' => sub {
    my $c = shift;
    return machine_is_public($c);
};

get '/machine/public/#id/#value' => sub {
732
733
734
735
    my $c = shift;
    return machine_is_public($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
736
get '/machine/set/#id/#field/#value' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
737
738
    my %privileged = map { $_ => 1 } qw(timeout id_owner);

Francesc Guasch's avatar
Francesc Guasch committed
739
740
741
742
743
744
    my $c = shift;
    my $id = $c->stash('id');
    my $field = $c->stash('field');
    my $value = $c->stash('value');

    return access_denied($c)       if !$USER->can_manage_machine($c->stash('id'));
Francesc Guasch's avatar
Francesc Guasch committed
745
    return access_denied($c) if $privileged{$field} && !$USER->is_admin;
Francesc Guasch's avatar
Francesc Guasch committed
746
747

    my $domain = Ravada::Front::Domain->open($id) or die "Unkown domain $id";
Francesc Guasch's avatar
Francesc Guasch committed
748
749
    $USER->send_message("Setting $field to $value in ".$domain->name)
        if $domain->_data($field) ne $value;
Francesc Guasch's avatar
Francesc Guasch committed
750
751
752
    return $c->render(json => { $field => $domain->_data($field, $value)});
};

753
754
755
756
757
758
759
760
761
762
get '/machine/autostart/#id/#value' => sub {
    my $c = shift;
    my $req = Ravada::Request->domain_autostart(
        id_domain => $c->stash('id')
           ,value => $c->stash('value')
             ,uid => $USER->id
    );
    return $c->render(json => { request => $req->id});
};

763
get '/machine/display/(:id).vv' => sub {
764
765
766
767
768
769
770
771
772
773
774
775
    my $c = shift;

    my $id = $c->stash('id');

    my $domain = $RAVADA->search_domain_by_id($id);
    return $c->render(text => "unknown machine id=$id") if !$id;

    return access_denied($c)
        if $USER->id ne $domain->id_owner
        && !$USER->is_admin;

    $c->res->headers->content_type('application/x-virt-viewer');
776
777
        $c->res->headers->content_disposition(
        "inline;filename=".$domain->id.".vv");
778

779
    return $c->render(data => $domain->display_file($USER), format => 'vv');
780
781
};

Francesc Guasch's avatar
Francesc Guasch committed
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
get '/machine/display-tls/(:id)-tls.vv' => sub {
    my $c = shift;

    my $id = $c->stash('id');

    my $domain = $RAVADA->search_domain_by_id($id);
    return $c->render(text => "unknown machine id=$id") if !$id;

    return access_denied($c)
        if $USER->id ne $domain->id_owner
        && !$USER->is_admin;

    $c->res->headers->content_type('application/x-virt-viewer');
        $c->res->headers->content_disposition(
        "inline;filename=".$domain->id."-tls.vv");

    return $c->render(data => $domain->display_file_tls($USER), format => 'vv');
};

Francesc Guasch's avatar
Francesc Guasch committed
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
# Network ##########################################################3

get '/network/interfaces/(:vm_type)/(:type)' => sub {
    my $c = shift;

    my $vm_type = $c->stash('vm_type');
    my $type = $c->stash('type');

    return $c->render( json => $RAVADA->list_network_interfaces(
               user => $USER
              ,type => $type
           ,vm_type => $vm_type
       )
    );
};
Francesc Guasch's avatar
Francesc Guasch committed
816

817
818
# Users ##########################################################3

Laura Figuerola's avatar
Laura Figuerola committed
819
820
##add user

821
any '/users/register' => sub {
822

Laura Figuerola's avatar
Laura Figuerola committed
823
       my $c = shift;
824
       return access_denied($c) if !$USER->is_admin();
Laura Figuerola's avatar
Laura Figuerola committed
825
826
827
       return register($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
828
829
any '/admin/user/(:id).(:type)' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
830
    return access_denied($c) if !$USER->can_manage_users() && !$USER->can_grant();
Francesc Guasch's avatar
Francesc Guasch committed
831
832
833
834
835
836

    my $user = Ravada::Auth::SQL->search_by_id($c->stash('id'));

    return $c->render(text => "Unknown user id: ".$c->stash('id'))
        if !$user;

Francesc Guasch's avatar
Francesc Guasch committed
837
838
839
840
841
    if ($c->param('make_admin')) {
        $USER->make_admin($c->stash('id'))  if $c->param('is_admin');
        $USER->remove_admin($c->stash('id'))if !$c->param('is_admin');
        $user = Ravada::Auth::SQL->search_by_id($c->stash('id'));
    }
842
843
844
845
846
847
848
849
850
851
852
    if ($c->param('grant')) {
        return access_denied($c)    if !$USER->can_grant();
        my %grant;
        for my $param_name (@{$c->req->params->names}) {
            if ( $param_name =~ /^perm_(.*)/ ) {
                $grant{$1} = 1;
            } elsif ($param_name =~ /^off_perm_(.*)/) {
                $grant{$1} = 0 if !exists $grant{$1};
            }
        }
        for my $perm (keys %grant) {
853
            if ( $grant{$perm} ) {
854
855
856
857
858
859
                $USER->grant($user, $perm);
            } else {
                $USER->revoke($user, $perm);
            }
        }
    }
Francesc Guasch's avatar
Francesc Guasch committed
860
861
862
    $c->stash(user => $user);
    return $c->render(template => 'main/manage_user');
};
Laura Figuerola's avatar
Laura Figuerola committed
863

fv3rdugo's avatar
fv3rdugo committed
864
865
866
867
868
869
870
871
##add notices in view machine

any '/admin/notices' => sub {
    my $c = shift;

    $c->render(template => 'main/notices');
};

872
873
874
875
876
877
878
879
880
881
882
883
884
885
get '/list_ldap_attributes/(#cn)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $cn = $c->stash('cn');
    my $user;
    eval {
        ($user) = Ravada::Auth::LDAP::search_user($cn);
    };
    return $c->render(json => { error => $@ }) if $@;
    return $c->render(json => []) if !$user;

    $c->session(ldap_attributes_cn => $cn) if $user;
886
    return $c->render(json => {attributes => [sort $user->attributes]});
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
};

get '/count_ldap_entries/(#attribute)/(#value)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my @entries;
    eval {
        @entries = Ravada::Auth::LDAP::search_user(
            field => $c->stash('attribute')
            ,name => $c->stash('value')
            ,typesonly => 1
        );
    };
    @entries = [ 'too many' ] if $@ =~ /Sizelimit exceeded/;
    return $c->render(json => { entries => scalar @entries });
};

Francesc Guasch's avatar
Francesc Guasch committed
906
post '/machine/add_access/(#id_domain)' => sub {
907
908
909
910
911
912
913
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

Francesc Guasch's avatar
Francesc Guasch committed
914
915
916
917
918
919
920
921
    my $args = decode_json($c->req->body);

    my $attribute = delete $args->{attribute};
    my $value = delete $args->{value};
    my $type = delete $args->{type};

    my $allowed = delete $args->{allowed};
    if (!defined $allowed || !$allowed || $allowed =~ /false|undefined/) {
922
        $allowed = 0;
Francesc Guasch's avatar
Francesc Guasch committed
923
924
    } else {
        $allowed= 1;
925
    }
Francesc Guasch's avatar
Francesc Guasch committed
926
927
    my $last = delete $args->{last};
    if (!defined $last || !$last || $last =~ /false|undefined/) {
928
        $last = 0;
Francesc Guasch's avatar
Francesc Guasch committed
929
930
    } else {
        $last = 1;
931
    }
Francesc Guasch's avatar
Francesc Guasch committed
932
933
934
935
936
937
938
939
940
941
    confess "Error: unknown args ".Dumper($args) if keys %$args;

    $domain->grant_access(type => $type
            , attribute => $attribute
            , allowed => $allowed
            , value => $value
            , last => $last
    );
    _fix_default_ldap_access($c, $domain, $allowed)
    if $type eq 'ldap';
942
943
944
945
946

    return $c->render(json => { ok => 1 });

};

Francesc Guasch's avatar
Francesc Guasch committed
947
sub _fix_default_ldap_access($c, $type, $domain, $allowed) {
948
949
950
951
952
953
954
955
956
957
958
959
960
    my @list = $domain->list_ldap_access();
    my $default_found;
    for ( @list ) {
        if ( $_->{value} eq '*' ) {
            $default_found = $_->{id};
        }
    }
    if ( $default_found ) {
        $domain->move_ldap_access($default_found, +1);
        return;
    }
    my $allowed_default = 0;
    $allowed_default = 1 if !$allowed;
Francesc Guasch's avatar
Francesc Guasch committed
961
962
963
964
965
966
    eval { $domain->grant_access(type => $type
            , attribute => 'DEFAULT'
            , value => '*'
            , last => $allowed_default
    ) };
    die $@ if $@;
967
968
969
970
971
972
973
974
975
976
977
978
}

get '/delete_ldap_access/(#id_domain)/(#id_access)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    $domain->delete_ldap_access($c->stash('id_access'));

979
980
981
982
983
984
    # delete default if it is the only one left
    my @ldap_access = $domain->list_ldap_access();
    if (scalar @ldap_access == 1 && $ldap_access[0]->{value} eq '*') {
        $domain->delete_ldap_access($ldap_access[0]->{id});
    }

985
986
987
988
989
990
991
992
993
994
995
996
997
    return $c->render(json => { ok => 1 });
};

get '/list_ldap_access/(#id_domain)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    my @ldap_access = $domain->list_ldap_access();
    my $default = {};
998
    if (scalar @ldap_access && $ldap_access[-1]->{value} eq '*') {
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
        $default = pop @ldap_access;
    }
    return $c->render(json => {list => \@ldap_access, default => $default} );
};

get '/move_ldap_access/(#id_domain)/(#id_access)/(#count)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    $domain->move_ldap_access($c->stash('id_access'), $c->stash('count'));

    return $c->render(json => { ok => 1});
};

1017
get '/set_ldap_access/(#id_domain)/(#id_access)/(#allowed)/(#last)' => sub {
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    my $allowed = $c->stash('allowed');
    if ($allowed =~ /false/ || !$allowed) {
        $allowed = 0;
    } else {
        $allowed = 1;
    }
1031
1032
1033
1034
1035
1036
1037
    my $last= $c->stash('last');
    if ($last=~ /false/ || !$last) {
        $last= 0;
    } else {
        $last= 1;
    }
    warn "last = $last";
1038

1039
    $domain->set_ldap_access($c->stash('id_access'), $allowed, $last);
1040
1041
    return $c->render(json => { ok => 1});
};
Francesc Guasch's avatar
Francesc Guasch committed
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067

get '/machine/set_access/(#id_domain)/(#id_access)/(#allowed)/(#last)' => sub {
    my $c = shift;

    return _access_denied($c) if !$USER->is_admin;

    my $domain_id = $c->stash('id_domain');
    my $domain = Ravada::Front::Domain->open($domain_id);

    my $allowed = $c->stash('allowed');
    if ($allowed =~ /false|undefined/ || !$allowed) {
        $allowed = 0;
    } else {
        $allowed = 1;
    }
    my $last= $c->stash('last');
    if ($last=~ /false|undefined/ || !$last) {
        $last= 0;
    } else {
        $last= 1;
    }

    $domain->set_access($c->stash('id_access'), $allowed, $last);
    return $c->render(json => { ok => 1});
};

1068
##############################################
Laura Figuerola's avatar
Laura Figuerola committed
1069

Francesc Guasch's avatar
Francesc Guasch committed
1070
1071
post '/request/(:name)/' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
1072
    my $name = $c->stash('name');
Francesc Guasch's avatar
Francesc Guasch committed
1073
1074
1075

    my $args = decode_json($c->req->body);

Francesc Guasch's avatar
Francesc Guasch committed
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
    for (qw(remote_ip uid)) {
        confess "Error: $_ should not be provided".Dumper($args)
        if exists $args->{$_};
    }
    if ($name eq 'start_clones') {
        $args->{remote_ip} = _remote_ip($c);
    }

    my $req;
    eval {
        $req = Ravada::Request->new_request(
            $name
            ,uid => $USER->id
            ,%$args
        );
    };
    return $c->render(json => { ok => 0, error => $@ }) if !$req;
    return $c->render(json => { ok => 1, request => $req->id });
Francesc Guasch's avatar
Francesc Guasch committed
1094
};
1095

1096
get '/request/(:id).(:type)' => sub {
1097
    my $c = shift;
1098
    my $id = $c->stash('id');
1099

Francesc Guasch's avatar
Francesc Guasch committed
1100
1101
1102
    if (!$USER) {
        $USER = _get_anonymous_user($c) or access_denied($c);
    }
1103
1104
1105
1106
    if ($c->stash('type') eq 'json') {
        my $request = Ravada::Request->open($id);
        return $c->render(json => $request->info($USER));
    }
1107
1108
1109
    return _show_request($c,$id);
};

1110
1111
1112
1113
1114
1115
1116
1117
1118
get '/anonymous/request/(:id).(:type)' => sub {
    my $c = shift;
    my $id = $c->stash('id');

    $USER = _anonymous_user($c);

    return _show_request($c,$id);
};

Francesc Guasch's avatar
Francesc Guasch committed
1119
1120
get '/requests.json' => sub {
    my $c = shift;