rvd_front 75.8 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
                                              ,widget => ''
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
76
77
78
79
80
                                              ,log => {
                                                log => 0
                                                ,file => '/var/log/ravada/rvd_front.log'
                                                ,level => 'debug'
                                              }
amesones's avatar
amesones committed
81
                                              }
Francesc Guasch's avatar
Francesc Guasch committed
82
                                      ,file => $FILE_CONFIG
83
};
84

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

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

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

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

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

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

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

Francesc Guasch's avatar
Francesc Guasch committed
129
130
init();
############################################################################3
131

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

136
137
138
hook before_routes => sub {
  my $c = shift;

139
140
  $USER = undef;

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

163
164
    $USER = _logged_in($c);

165
166
167
168
169
    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};

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

173
    return if $url =~ m{^/(login|logout|requirements|robots.txt|favicon.ico)};
174
175
176
177
178
179
180
181

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

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


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

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

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

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

221
222
any '/login' => sub {
    my $c = shift;
223
    return login($c);
224
225
};

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

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

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

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

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

264
    $c->stash(_anonymous => 1 , _logged_in => 0);
265
    _init_error($c);
266
    my $base_id = $c->stash('base_id');
267
268
    my $base = $RAVADA->search_domain_by_id($base_id);

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

273
274
275
276
277
278
279
280
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);

281
    $RAVADA->update_settings_global($arg, $USER);
282
283
284
285

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

286
any '/admin/#type' => sub {
287
  my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
288

289
290
291
  return admin($c)  if $c->stash('type') eq 'machines'
                        && $USER->is_operator;

292
293
  return access_denied($c)    if !$USER->is_operator;

amesones's avatar
amesones committed
294
  return admin($c);
Francesc Guasch's avatar
Francesc Guasch committed
295
296
};

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

303
304
305
306
307
any '/copy_machine' => sub {
    my $c = shift;
    return new_machine_copy($c);
};

308
get '/domain/new.html' => sub {
Francesc Guasch's avatar
Francesc Guasch committed
309
310
    my $c = shift;

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

};

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

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

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

Francesc Guasch's avatar
Francesc Guasch committed
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
389
390
391
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 });

};

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


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

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

431
432
433
434
};

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

elodin1's avatar
elodin1 committed
436
437
438
    return access_denied($c) unless _logged_in($c)
        && $USER->can_create_machine();

439
440
441
    my $vm_name = $c->param('backend');

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

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

453
get '/list_machines.json' => sub {
454
    my $c = shift;
455

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

465
    return $c->render( json => $RAVADA->list_machines($USER) );
466

467
};
Francesc Guasch's avatar
Francesc Guasch committed
468

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

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

486
487
# machine commands

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

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

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

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

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

Francesc Guasch's avatar
Francesc Guasch committed
510
511
    $c->render(json => $RAVADA->list_requests($id_domain,10));
};
joelalju's avatar
joelalju committed
512

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

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

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

529
530
    return $c->redirect_to('/login') if !_logged_in($c);

joelalju's avatar
joelalju committed
531
532
533
534
535
536
    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;

537
538
539
    return view_machine($c);
};

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

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

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

        return shutdown_machine($c);
};

563
564
565
566
567
568
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);
};
569
any '/machine/remove/(:id).(:type)' => sub {
joansp's avatar
joansp committed
570
        my $c = shift;
571
    return access_denied($c)       if !$USER->can_remove_machine($c->stash('id'));
joansp's avatar
joansp committed
572
573
        return remove_machine($c);
};
574
575

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

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

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

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

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

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

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

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

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

636
637
638
        return hybernate_machine($c);
};

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

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

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

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

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
750
751
752
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 });

};

Francesc Guasch's avatar
Francesc Guasch committed
753
754
755
756
757
758
759
760
get '/machine/compact/(#id_domain)' => sub($c) {
    my $req = Ravada::Request->compact(
        id_domain => $c->stash('id_domain')
        ,uid => $USER->id
    );
    return $c->render(json => { request => $req->id });
};

761
762
763
764
765
766
767
get '/node/exists/#name' => sub {
    my $c = shift;
    my $name = $c->stash('name');

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

};
768
get '/machine/rename/#id/#value' => sub {
769
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
770
    return access_denied($c)       if !$USER->can_manage_machine($c->stash('id'));
771
772
773
    return rename_machine($c);
};

774
775
any '/machine/copy' => sub {
    my $c = shift;
776
    return access_denied($c)    if !$USER -> can_clone_all();
777
778
779
    return copy_machine($c);
};

780
781
782
783
784
785
get '/machine/public/#id' => sub {
    my $c = shift;
    return machine_is_public($c);
};

get '/machine/public/#id/#value' => sub {
786
787
788
789
    my $c = shift;
    return machine_is_public($c);
};

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

Francesc Guasch's avatar
Francesc Guasch committed
793
794
795
796
797
798
    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'));
799
    return access_denied($c) if $privileged{$field} && !$USER->is_admin;
Francesc Guasch's avatar
Francesc Guasch committed
800
801

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

807
808
809
810
811
812
813
814
815
816
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});
};

817
get '/machine/display/(:id).vv' => sub {
818
819
820
821
822
823
824
825
826
827
828
829
    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');
830
831
        $c->res->headers->content_disposition(
        "inline;filename=".$domain->id.".vv");
832

833
    return $c->render(data => $domain->display_file($USER), format => 'vv');
834
835
};

Francesc Guasch's avatar
Francesc Guasch committed
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
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
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# 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
870

871
872
# Users ##########################################################3

Laura Figuerola's avatar
Laura Figuerola committed
873
874
##add user

875
any '/users/register' => sub {
876

Laura Figuerola's avatar
Laura Figuerola committed
877
       my $c = shift;
878
       return access_denied($c) if !$USER->is_admin();
Laura Figuerola's avatar
Laura Figuerola committed
879
880
881
       return register($c);
};

Francesc Guasch's avatar
Francesc Guasch committed
882
883
any '/admin/user/(:id).(:type)' => sub {
    my $c = shift;
Francesc Guasch's avatar
Francesc Guasch committed
884
    return access_denied($c) if !$USER->can_manage_users() && !$USER->can_grant();
Francesc Guasch's avatar
Francesc Guasch committed
885
886
887
888
889
890

    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
891
892
893
894
895
    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'));
    }
896
897
898
899
900
901
902
903
904
905
906
    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) {
907
            if ( $grant{$perm} ) {
908
909
910
911
912
913
                $USER->grant($user, $perm);
            } else {
                $USER->revoke($user, $perm);
            }
        }
    }
Francesc Guasch's avatar
Francesc Guasch committed
914
915
916
    $c->stash(user => $user);
    return $c->render(template => 'main/manage_user');
};
Laura Figuerola's avatar
Laura Figuerola committed
917

918
919
920
921
922
923
get '/list_ldap_attributes/(#cn)' => sub {
    my $c = shift;

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

    my $cn = $c->stash('cn');
924
925
    return $c->render(json => $LDAP_ATTRIBUTES{$cn}) if exists $LDAP_ATTRIBUTES{$cn};

926
927
928
929
    my $user;
    eval {
        ($user) = Ravada::Auth::LDAP::search_user($cn);
    };
930
931
932
933
934
935
936
937
938
939
    my $return;
    if ( $@ ) {
        my $error = $@;
        $error =~ s/(.*) at lib\/Ravada.*/$1/;
        $return = { error => $error };
    } elsif (!$user) {
        $return = { error => "User not found" };
    } else {
        $return = {attributes => [sort $user->attributes]};
    }
940
941

    $c->session(ldap_attributes_cn => $cn) if $user;
942
943
944
    $LDAP_ATTRIBUTES{$cn} = $return;

    return $c->render( json => $return );
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
};

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

964
post '/machine/add_access/(#id_domain)' => sub {
965
966
967
968
969
970
971
    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);

972
973
974
975
976
977
978
979
    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/) {
980
        $allowed = 0;
981
982
    } else {
        $allowed= 1;
983
    }
984
985
    my $last = delete $args->{last};
    if (!defined $last || !$last || $last =~ /false|undefined/) {
986
        $last = 0;
987
988
    } else {
        $last = 1;
989
    }
990
991
992
993
994
995
996
997
998
999
    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';
1000

For faster browsing, not all history is shown. View entire blame