rvd_front 74.2 KB
Newer Older
1
2
3
#!/usr/bin/env perl
use warnings;
use strict;
4
5
6
#####
use locale ':not_characters';
#####
7

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

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

27

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

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

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

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

my $FILE_CONFIG_RAVADA;
48
for my $file ( "/etc/ravada.conf" , ($ENV{HOME} or '')."/ravada.conf") {
49
50
51
    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
52
}
53

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

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#####
#####
#####
# 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);
#####
#####
#####
106
plugin I18N => {namespace => 'Ravada::I18N', default => 'en'};
Francesc Guasch's avatar
Francesc Guasch committed
107

108
my %config;
109
%config = (config => $CONFIG_FRONT->{config}) if $CONFIG_FRONT->{config};
robertperez-upc's avatar
robertperez-upc committed
110

111
our $RAVADA = Ravada::Front->new(%config);
112

113
our $USER;
Francesc Guasch's avatar
Francesc Guasch committed
114

115
# TODO: get those from the config file
116
our $DOCUMENT_ROOT = "/var/www";
117
118

# session times out in 5 minutes
119
our $SESSION_TIMEOUT = ($CONFIG_FRONT->{session_timeout} or 5 * 60);
120
# session times out in 15 minutes for admin users
121
our $SESSION_TIMEOUT_ADMIN = ($CONFIG_FRONT->{session_timeout_admin} or 15 * 60);
122
our $SESSION_TIMEOUT_ADMIN2 = ($CONFIG_FRONT->{session_timeout_admin2} or 60 * 60);
123

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

Francesc Guasch's avatar
Francesc Guasch committed
127
128
init();
############################################################################3
129

130
131
132
133
sub _time() {
    return strftime('%Y/%m/%d:%H:%M:%S %z',localtime);
}

134
135
136
hook before_routes => sub {
  my $c = shift;

137
138
  $USER = undef;

Francesc Guasch's avatar
Francesc Guasch committed
139
  $c->stash(version => $RAVADA->version);
140
  my $url = $c->req->url->to_abs->path;
fv3rdugo's avatar
fv3rdugo committed
141
  my $host = $c->req->url->to_abs->host;
142
  $c->stash(css=>['/css/sb-admin.css']
Francesc Guasch's avatar
Francesc Guasch committed
143
144
            ,js=>[
                '/js/ravada.js'
145
146
147
                ]
            ,csssnippets => []
            ,navbar_custom => 0
Francesc Guasch's avatar
Francesc Guasch committed
148
149
150
151
            ,url => undef
            ,_logged_in => undef
            ,_anonymous => undef
            ,_user => undef
152
            ,footer=> $CONFIG_FRONT->{footer}
153
            ,monitoring => 0
fv3rdugo's avatar
fv3rdugo committed
154
            ,fallback => $CONFIG_FRONT->{fallback}
155
            ,check_netdata => 0
156
            ,guide => $CONFIG_FRONT->{guide}
fv3rdugo's avatar
fv3rdugo committed
157
            ,host => $host
158
            );
159

160
161
    $USER = _logged_in($c);

162
163
164
165
166
    my $user = '-';
    $user = $USER->name if defined $USER;
    app->log->info(_remote_ip($c)." $user ["._time()."] ".$c->req->method." ".$url)
    if $CONFIG_FRONT->{log}->{log};

167
    return if $url =~ m{^/(css|font|img|js)}
Francesc Guasch's avatar
Francesc Guasch committed
168
	   || $url =~ m{^/fallback/.*\.(css|js|map)$};
169

170
171
172
173
174
175
176
177
178
    return if $url =~ m{^/(login|logout|requirements|robots.txt)};

    if ( $RAVADA->is_in_maintenance ) {
        return login($c) if !$USER && $url =~ m{^/$};
        return maintenance($c) if !$USER || !$USER->is_operator;
    }

    return if $url =~ m{^/anonymous};

Francesc Guasch's avatar
Francesc Guasch committed
179
180
    if (($url =~ m{^/machine/(clone|display|info|view)/}
        || $url =~ m{^/(list_bases_anonymous|request/)}i
181
        || $url =~ m{^/ws/subscribe}
Francesc Guasch's avatar
Francesc Guasch committed
182
183
184
185
186
187
        ) && !_logged_in($c)) {
        $USER = _anonymous_user($c);
        return if $USER->is_temporary;
    }
    return access_denied($c)
        if $url =~ /(screenshot|\.json)/
188
        && !_logged_in($c);
189
    return login($c,401) if !_logged_in($c);
190

191
192
193
194
195
196
    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');
    }
197
        $c->stash( fallback => 1) if $c->session('fallback');
198
199
200
201
202
};


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

Francesc Guasch's avatar
Francesc Guasch committed
203
204
205
206
207
any '/robots.txt' => sub {
    my $c = shift;
    return $c->render(text => "User-agent: *\nDisallow: /\n", format => 'text');
};

208
any '/' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
209
    my $c = shift;
210
    return quick_start($c);
Francesc Guasch's avatar
Francesc Guasch committed
211
212
};

Francesc Guasch's avatar
Francesc Guasch committed
213
214
any '/index.html' => sub {
    my $c = shift;
215
    return quick_start($c);
Francesc Guasch's avatar
Francesc Guasch committed
216
217
};

218
219
any '/login' => sub {
    my $c = shift;
220
    return login($c);
221
222
};

Francesc Guasch's avatar
Francesc Guasch committed
223
224
225
226
227
228
229
230
231
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
232
233
234
235
236
    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
237
238
};

Francesc Guasch's avatar
Francesc Guasch committed
239
240
any '/logout' => sub {
    my $c = shift;
241
    logout($c);
Francesc Guasch's avatar
Francesc Guasch committed
242
243
244
    $c->redirect_to('/');
};

245
get '/anonymous' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
246
    my $c = shift;
247
#    $c->render(template => 'bases', base => list_bases());
248
    $USER = _anonymous_user($c);
249
    return list_bases_anonymous($c);
Francesc Guasch's avatar
Francesc Guasch committed
250
251
};

252
get '/anonymous_logout.html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
253
    my $c = shift;
254
255
    $c->session('anonymous_user' => '');
    return $c->redirect_to('/');
Francesc Guasch's avatar
Francesc Guasch committed
256
257
};

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

261
    $c->stash(_anonymous => 1 , _logged_in => 0);
262
    _init_error($c);
263
    my $base_id = $c->stash('base_id');
264
265
    my $base = $RAVADA->search_domain_by_id($base_id);

266
    $USER = _anonymous_user($c);
267
    return quick_start_domain($c,$base->id, $USER->name);
Francesc Guasch's avatar
Francesc Guasch committed
268
269
};

270
271
272
273
274
275
276
277
get '/settings_global.json' => sub($c) {
    $RAVADA->is_in_maintenance();
    return $c->render(json => $RAVADA->settings_global );
};

post '/settings_global' => sub($c) {
    my $arg = decode_json($c->req->body);

278
    $RAVADA->update_settings_global($arg, $USER);
279
280
281
282

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

283
any '/admin/#type' => sub {
284
  my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
285

286
287
288
  return admin($c)  if $c->stash('type') eq 'machines'
                        && $USER->is_operator;

289
290
  return access_denied($c)    if !$USER->is_operator;

amesones's avatar
amesones committed
291
  return admin($c);
Francesc Guasch's avatar
Francesc Guasch committed
292
293
};

294
any '/new_machine' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
295
    my $c = shift;
296
    return access_denied($c)    if !$USER->can_create_machine;
297
    return new_machine($c);
Francesc Guasch's avatar
Francesc Guasch committed
298
299
};

300
301
302
303
304
any '/copy_machine' => sub {
    my $c = shift;
    return new_machine_copy($c);
};

305
get '/domain/new.html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
306
307
    my $c = shift;

308
309
    return access_denied($c) if !_logged_in($c) || !$USER->is_admin();
    $c->stash(error => []);
amesones's avatar
amesones committed
310
    return $c->render(template => "main/new_machine");
Francesc Guasch's avatar
Francesc Guasch committed
311
312
313

};

314
315
get '/list_vm_types.json' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
316
    $c->render(json => $RAVADA->list_vm_types);
317
318
};

319
320
321
322
323
324
325
326
327
328
329
330
331
332
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;
333
334
335
336
337

    my $machines = $RAVADA->_list_machines_vm($c->stash('id'));
    for ( @$machines ) {
        my $req = Ravada::Request->shutdown_domain( uid => $USER->id , id_domain => $_->{id} );
    }
338
339
    return $c->render(json => {enabled => $RAVADA->enable_node($c->stash('id'),0)});
};
340
341
342
343
344
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)});
};
345

Francesc Guasch's avatar
Francesc Guasch committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
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 });

};

389
390
391
392
393
394
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
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
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 });
};


415
416
get '/list_bases.json' => sub {
    my $c = shift;
417
418
419
420
421
422
423
424
425
426
427

    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]);

428
429
430
431
};

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

elodin1's avatar
elodin1 committed
433
434
435
    return access_denied($c) unless _logged_in($c)
        && $USER->can_create_machine();

436
437
438
    my $vm_name = $c->param('backend');

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

441
get '/iso_file.json' => sub {
joelalju's avatar
joelalju committed
442
    my $c = shift;
elodin1's avatar
elodin1 committed
443
444
    return access_denied($c) unless _logged_in($c)
        && $USER->can_create_machine();
445
    my @isos =('<NONE>');
Fernando Verdugo's avatar
Fernando Verdugo committed
446
    push @isos,(@{$RAVADA->iso_file('KVM')});
447
    $c->render(json => \@isos);
joelalju's avatar
joelalju committed
448
449
};

450
get '/list_machines.json' => sub {
451
    my $c = shift;
452

453
    return access_denied($c) unless _logged_in($c)
454
455
456
457
458
        && (
            $USER->can_list_machines
            || $USER->can_list_own_machines()
            || $USER->can_list_clones()
            || $USER->can_list_clones_from_own_base()
459
460
461
            || $USER->is_admin()
        );

462
    return $c->render( json => $RAVADA->list_machines($USER) );
463

464
};
Francesc Guasch's avatar
Francesc Guasch committed
465

466
467
468
get '/list_machines_user.json' => sub {
    my $c = shift;
    return $c->render( json => $RAVADA->list_machines_user($USER));
469
};
Francesc Guasch's avatar
Francesc Guasch committed
470

471
472
473
474
475
476
477
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
478
get '/list_lxc_templates.json' => sub {
fv3rdugo's avatar
fv3rdugo committed
479
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
480
    $c->render(json => $RAVADA->list_lxc_templates);
fv3rdugo's avatar
fv3rdugo committed
481
482
};

483
484
# machine commands

485
get '/machine/info/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
486
    my $c = shift;
487
    my $id = $c->stash('id');
Francesc Guasch's avatar
Francesc Guasch committed
488
    die "No id " if !$id;
489

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

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

495
496
    my $info = $domain->info($USER);
    if ($domain->is_active && !$info->{ip}) {
Francesc Guasch's avatar
Francesc Guasch committed
497
        Ravada::Request->refresh_machine(id_domain => $domain->id, uid => $USER->id);
498
499
    }
    return $c->render(json => $info);
Francesc Guasch's avatar
Francesc Guasch committed
500
501
};

Francesc Guasch's avatar
Francesc Guasch committed
502
get '/machine/requests/(:id).json' => sub {
503
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
504
    my $id_domain = $c->stash('id');
505
    return access_denied($c) unless $USER->can_manage_machine($id_domain);
joelalju's avatar
joelalju committed
506

Francesc Guasch's avatar
Francesc Guasch committed
507
508
    $c->render(json => $RAVADA->list_requests($id_domain,10));
};
joelalju's avatar
joelalju committed
509

510
any '/machine/manage/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
511
   	 my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
512
     Ravada::Request->refresh_machine(id_domain => $c->stash('id'), uid => $USER->id);
Francesc Guasch's avatar
Francesc Guasch committed
513
     return manage_machine($c);
514
};
joelalju's avatar
joelalju committed
515

Francesc Guasch's avatar
Francesc Guasch committed
516
517
518
any '/hardware/(:id).(:type)' => sub {
   	 my $c = shift;
     return $c->render(template => 'main/hardware');
519
520
};

521
get '/machine/view/(:id).(:type)' => sub {
522
    my $c = shift;
523
524
    my $id = $c->stash('id');
    my $type = $c->stash('type');
Francesc Guasch's avatar
Francesc Guasch committed
525

526
527
    return $c->redirect_to('/login') if !_logged_in($c);

joelalju's avatar
joelalju committed
528
529
530
531
532
533
    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;

534
535
536
    return view_machine($c);
};

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

Francesc Guasch's avatar
Francesc Guasch committed
540
541
542
543
544
545
546
547
548
549
550
    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);
551
};
Francesc Guasch's avatar
Francesc Guasch committed
552

553
get '/machine/shutdown/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
554
        my $c = shift;
555
    return access_denied($c)        if !$USER ->can_shutdown($c->stash('id'));
Francesc Guasch's avatar
Francesc Guasch committed
556
557
558
559

        return shutdown_machine($c);
};

560
561
562
563
564
565
get '/machine/force_shutdown/(:id).(:type)' => sub {
        my $c = shift;
    return access_denied($c)        if !$USER ->can_shutdown($c->stash('id'));

        return force_shutdown_machine($c);
};
566
any '/machine/remove/(:id).(:type)' => sub {
joansp's avatar
joansp committed
567
        my $c = shift;
568
    return access_denied($c)       if !$USER->can_remove_machine($c->stash('id'));
joansp's avatar
joansp committed
569
570
        return remove_machine($c);
};
571
572

any '/machine/remove_clones/(:id).(:type)' => sub {
573
574
575
576
577
578
    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
579
580
	        || $USER->can_remove_clone()
            || $USER->can_remove_all();
581
    return remove_clones($c);
582
583
};

584
get '/machine/prepare/(:id).(:type)' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
585
586
587
588
        my $c = shift;
        return prepare_machine($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
589
get '/machine/set_base_vm/(:id_vm)/(:id_domain).(:type)' => sub {
590
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
591
592
593
594
595
596
    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);
597
598
};

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

604
get '/machine/remove_base/(:id).(:type)' => sub {
605
606
607
608
    my $c = shift;
    return remove_base($c);
};

609
get '/machine/screenshot/(:id).(:type)' => sub {
610
        my $c = shift;
611
612
        my $domain = _search_requested_machine($c);
        return access_denied($c)   if (!$USER->can_screenshot() || $domain->is_base());
613
614
615
        return screenshot_machine($c);
};

616
get '/machine/copy_screenshot/(:id).(:type)' => sub {
617
618
619
        my $c = shift; 
        my $domain = _search_requested_machine($c);
        return access_denied($c) if (!$USER->is_admin() || $domain->id_base() == NULL );
620
621
622
        return copy_screenshot($c);
};

623
get '/machine/pause/(:id).(:type)' => sub {
joansp's avatar
joansp committed
624
625
626
627
        my $c = shift;
        return pause_machine($c);
};

628
get '/machine/hibernate/(:id).(:type)' => sub {
629
        my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
630
          return access_denied($c)
Francesc Guasch's avatar
Francesc Guasch committed
631
             unless $USER->is_admin() || $USER->can_shutdown($c->stash('id'));
Francesc Guasch's avatar
Francesc Guasch committed
632

633
634
635
        return hybernate_machine($c);
};

636
get '/machine/resume/(:id).(:type)' => sub {
joansp's avatar
joansp committed
637
638
639
640
        my $c = shift;
        return resume_machine($c);
};

641
get '/machine/start/(:id).(:type)' => sub {
joansp's avatar
joansp committed
642
643
644
        my $c = shift;
        return start_machine($c);
};
joansp's avatar
joansp committed
645

646
get '/machine/exists/#name' => sub {
647
    my $c = shift;
648
    my $name = $c->stash('name');
649
650
651
652
653
654
    #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
655

Francesc Guasch's avatar
Francesc Guasch committed
656
post '/machine/hardware/change' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
657
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
658
659
660
661
662
663
664
665
666
667
668
669
    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
670
    return $c->render(json => { req => Ravada::Request->change_hardware(
Francesc Guasch's avatar
Francesc Guasch committed
671
672
673
674
                id_domain => $domain->id
                ,hardware => $hardware
                ,index => $index
                ,data => $data
Francesc Guasch's avatar
Francesc Guasch committed
675
676
677
678
679
                ,uid => $USER->id
            )
    });
};

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
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
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 });

};

750
751
752
753
754
755
756
get '/node/exists/#name' => sub {
    my $c = shift;
    my $name = $c->stash('name');

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

};
757
get '/machine/rename/#id/#value' => sub {
758
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
759
    return access_denied($c)       if !$USER->can_manage_machine($c->stash('id'));
760
761
762
    return rename_machine($c);
};

763
764
any '/machine/copy' => sub {
    my $c = shift;
765
    return access_denied($c)    if !$USER -> can_clone_all();
766
767
768
    return copy_machine($c);
};

769
770
771
772
773
774
get '/machine/public/#id' => sub {
    my $c = shift;
    return machine_is_public($c);
};

get '/machine/public/#id/#value' => sub {
775
776
777
778
    my $c = shift;
    return machine_is_public($c);
};

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

Francesc Guasch's avatar
Francesc Guasch committed
782
783
784
785
786
787
    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'));
788
    return access_denied($c) if $privileged{$field} && !$USER->is_admin;
Francesc Guasch's avatar
Francesc Guasch committed
789
790

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

796
797
798
799
800
801
802
803
804
805
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});
};

806
get '/machine/display/(:id).vv' => sub {
807
808
809
810
811
812
813
814
815
816
817
818
    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');
819
820
        $c->res->headers->content_disposition(
        "inline;filename=".$domain->id.".vv");
821

822
    return $c->render(data => $domain->display_file($USER), format => 'vv');
823
824
};

Francesc Guasch's avatar
Francesc Guasch committed
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
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
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
# 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
859

860
861
# Users ##########################################################3

Laura Figuerola's avatar
Laura Figuerola committed
862
863
##add user

864
any '/users/register' => sub {
865

Laura Figuerola's avatar
Laura Figuerola committed
866
       my $c = shift;
867
       return access_denied($c) if !$USER->is_admin();
Laura Figuerola's avatar
Laura Figuerola committed
868
869
870
       return register($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
871
872
any '/admin/user/(:id).(:type)' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
873
    return access_denied($c) if !$USER->can_manage_users() && !$USER->can_grant();
Francesc Guasch's avatar
Francesc Guasch committed
874
875
876
877
878
879

    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
880
881
882
883
884
    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'));
    }
885
886
887
888
889
890
891
892
893
894
895
    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) {
896
            if ( $grant{$perm} ) {
897
898
899
900
901
902
                $USER->grant($user, $perm);
            } else {
                $USER->revoke($user, $perm);
            }
        }
    }
Francesc Guasch's avatar
Francesc Guasch committed
903
904
905
    $c->stash(user => $user);
    return $c->render(template => 'main/manage_user');
};
Laura Figuerola's avatar
Laura Figuerola committed
906

907
908
909
910
911
912
913
914
915
916
917
918
919
920
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;
921
    return $c->render(json => {attributes => [sort $user->attributes]});
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
};

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 });
};

941
post '/machine/add_access/(#id_domain)' => sub {
942
943
944
945
946
947
948
    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);

949
950
951
952
953
954
955
956
    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/) {
957
        $allowed = 0;
958
959
    } else {
        $allowed= 1;
960
    }
961
962
    my $last = delete $args->{last};
    if (!defined $last || !$last || $last =~ /false|undefined/) {
963
        $last = 0;
964
965
    } else {
        $last = 1;
966
    }
967
968
969
970
971
972
973
974
975
976
    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';
977
978
979
980
981

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

};

982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
get '/add_ldap_access/(#id_domain)/(#attribute)/(#value)/(#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 $attribute = $c->stash('attribute');
    my $value = $c->stash('value');
    my $allowed = 1;
    if ($c->stash('allowed') eq 'false') {
        $allowed = 0;
    }
    my $last = 1;
    if ($c->stash('last') eq 'false') {
        $last = 0;
    }
    $last = 1 if !$allowed;
For faster browsing, not all history is shown. View entire blame