#!/usr/local/bin/perl # Show a terminal that is connected to a Websockets server via Webmin proxying use strict; use warnings; no warnings 'uninitialized'; our $unsafe_index_cgi = 1; require './xterm-lib.pl'; ## no critic our (%in, %text, %config, %gconfig, %access, %module_info, $module_name, $module_config_directory, $module_var_directory, $remote_user); ReadParse(); $ENV{'HTTP_WEBMIN_PATH'} && error($text{'index_eproxy'}); # Check for needed modules my @modload = ( ['Digest::SHA', sub { eval { require Digest::SHA; Digest::SHA->import; 1 } }], ['Digest::MD5', sub { eval { require Digest::MD5; Digest::MD5->import; 1 } }], ['IO::Select', sub { eval { require IO::Select; IO::Select->import; 1 } }], ['Time::HiRes', sub { eval { require Time::HiRes; Time::HiRes->import; 1 } }], ['Net::WebSocket::Server', sub { eval { require Net::WebSocket::Server; Net::WebSocket::Server->import; 1 } }], ); foreach my $m (@modload) { my ($modname, $loader) = @$m; next if ($loader->()); ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0); my $missinglink = text('index_cpan', "$modname", "../cpan/download.cgi?source=3&cpan=$modname&mode=2&return=/$module_name/&returndesc=".urlize($module_info{'desc'})); if ($gconfig{'os_type'} eq 'redhat-linux') { $missinglink .= " ". text('index_epel', 'https://docs.fedoraproject.org/en-US/epel'); } elsif ($gconfig{'os_type'} eq 'suse-linux') { $missinglink = text('index_suse', "$modname", 'https://software.opensuse.org/download/package?package=perl-IO-Tty&project=devel%3Alanguages%3Aperl'); } if (get_product_name() eq 'usermin') { print text('index_missing', $modname) ."

\n"; } else { print $missinglink ."

\n"; } ui_print_footer("/", $text{'index'}); exit; } # Get Webmin current version for links serial my $wver = get_webmin_version(); $wver =~ s/\.//; # Build Xterm dependency links my $termlinks = { 'css' => ["xterm.css?$wver"], 'js' => ["xterm.js?$wver", "xterm-addon-attach.js?$wver", "xterm-addon-fit.js?$wver", "xterm-addon-webgl.js?$wver"] }; # Pre-process options my $conf_size_str = $config{'size'}; my $def_cols_n = 80; my $def_rows_n = 24; my $xmlhr = ($ENV{'HTTP_X_REQUESTED_WITH'} || '') eq "XMLHttpRequest"; my $font_size = $config{'fontsize'} || 14; # Parse module config my ($conf_cols_n, $conf_rows_n) = (($conf_size_str || '') =~ /([\d]+)X([\d]+)/i); $conf_cols_n = int($conf_cols_n); $conf_rows_n = int($conf_rows_n); # Set columns and rows vars my $env_cols = $conf_cols_n || $def_cols_n; my $env_rows = $conf_rows_n || $def_rows_n; # Set columns and rows environment vars only # in fixed mode, and only for old themes if ($conf_cols_n && $conf_rows_n && !$xmlhr) { $ENV{'COLUMNS'} = $conf_cols_n; $ENV{'LINES'} = $conf_rows_n; } # Define columns and rows my $conf_screen_reader = $config{'screen_reader'} eq 'true' ? 'true' : 'false'; my %term_opts; $term_opts{'Options'} = "{ cols: $env_cols, rows: $env_rows, ". "screenReaderMode: $conf_screen_reader, ". "overviewRuler: { width: 9 }, ". "fontSize: $font_size }"; my $term_size = " min-width: ".($conf_cols_n ? "".($conf_cols_n * 9)."px" : "calc(100vw - 22px)")."; max-width: ".($conf_cols_n ? "".($conf_cols_n * 9)."px" : "calc(100vw - 22px)")."; min-height: ".($conf_rows_n ? "".($conf_rows_n * 18)."px" : "calc(100vh - 55px)")."; max-height: ".($conf_rows_n ? "".($conf_rows_n * 18)."px" : "calc(100vh - 55px)").";"; # Tweak old themes inline my $styles_inline = < .terminal { visibility: hidden; animation: .15s fadeIn; animation-fill-mode: forwards; } \@keyframes fadeIn { 99% { visibility: hidden; } 100% { visibility: visible; } } EOF # Print header ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0, undef, "{'css'}[0]\">\n". "\n". "\n". "\n". "\n" ); # Print main container print "

\n"; # Get a free port that can be used for the socket my $port = allocate_miniserv_websocket($module_name); # Decide which Unix account the terminal will run as my $user = resolve_shell_user(\%access, $remote_user, \%in, \%config); my @uinfo = getpwnam($user); @uinfo || error(text('index_euser', html_escape($user))); # Check for directory to start the shell in my $dir = $in{'dir'}; # Launch the shell server on the allocated port my $shellserver_cmd = "$module_config_directory/shellserver.pl"; if (!-r $shellserver_cmd) { create_wrapper($shellserver_cmd, $module_name, "shellserver.pl"); } $ENV{'SESSION_ID'} = $main::session_id; system_logged($shellserver_cmd." ".quotemeta($port)." ".quotemeta($user). ($dir ? " ".quotemeta($dir) : ""). " >$module_var_directory/websocket-connection-$port.out 2>&1 {'js'}[3]; my $term_script = <'; }; socket.onclose = function() { termcont.innerHTML = 'Error: ' + err_conn_lost + ''; }; })(); EOF # Return inline script data depending on type print "\n"; ui_print_footer();