HTML; } function GetProxies() { $output = shell_exec("if test -f /lsiopy/bin/python3; then /lsiopy/bin/python3 /dashboard/swag-proxies.py fast; else python3 /dashboard/swag-proxies.py fast; fi"); $results = json_decode($output); $status = ""; $index = 0; foreach($results as $result => $data){ $tr_class = ($index % 2 == 0) ? 'shaded' : ''; $status .= ''.$result.''; if ($data->status == 1) { $status .= ''; } else { $status .= ''; } $status .= ''; if (!empty($data->locations)) { $locations = $data->locations; $location = implode(",", $locations); $status .= ''; $auths = implode(PHP_EOL, $data->auths); if ($data->auth_status == 1) { $status .= ''; } else { $status .= ''; } $status .= ''.$location.''; } else { $error = 'Unable to locate the proxy config for '.$result.', it must use the following structure:'.PHP_EOL; $error .= ' set $upstream_app ;'.PHP_EOL; $error .= ' set $upstream_port ;'.PHP_EOL; $error .= ' set $upstream_proto ;'.PHP_EOL; $error .= ' proxy_pass $upstream_proto://$upstream_app:$upstream_port;'.PHP_EOL; $status .= ''; } $status .= ''; $index++; } return <<

Proxies

Scanning for unproxied containers ...

{$status}

Application

Available

Proxied

Auth

Location



HTML; } function GetF2B() { $output = shell_exec("if test -f /lsiopy/bin/python3; then /lsiopy/bin/python3 /dashboard/swag-f2b.py; else python3 /dashboard/swag-f2b.py; fi"); $jails = json_decode($output, true); $status = ""; $index = 0; foreach($jails as $jail){ $tr_class = ($index % 2 == 0) ? 'shaded' : ''; $data = ($jail["data"]) ? ' ' : ''; $status .= ''.$jail["name"].''; $status .= ''.$jail["bans"].''; $status .= ''.$jail["last_ban"].''.$data.''; $index++; } return <<

Fail2Ban

{$status}

Jail

Bans

Last



HTML; } function GetTemplates() { $tooltip = ""; $files = ""; $counter = 1; $conf_locations = array( ".conf" => "https://github.com/linuxserver/docker-swag/blob/master/root/defaults/nginx/", "subdomain.conf" => "https://github.com/linuxserver/reverse-proxy-confs/blob/master/", "subfolder.conf" => "https://github.com/linuxserver/reverse-proxy-confs/blob/master/", "dashboard.subdomain.conf" => "https://github.com/linuxserver/docker-mods/blob/swag-dashboard/root/dashboard/", "nginx.conf" => "https://github.com/linuxserver/docker-baseimage-alpine-nginx/tree/master/root/defaults/nginx/", "ssl.conf" => "https://github.com/linuxserver/docker-baseimage-alpine-nginx/tree/master/root/defaults/nginx/", "default.conf" => "https://github.com/linuxserver/docker-swag/blob/master/root/defaults/nginx/site-confs/", ); $output = shell_exec("/etc/s6-overlay/s6-rc.d/init-version-checks/run"); foreach(explode(PHP_EOL, $output) as $line) { if(substr($line, 0, 1) === "*"){ $tooltip .= str_replace("*", "", $line).PHP_EOL; } elseif(str_contains($line, "/config/")) { $tr_class = ($counter % 2 == 0) ? 'shaded' : ''; $clean_line = htmlspecialchars($line); list($old_date, $new_date, $path) = explode(' │ ', $clean_line); $old_date = trim($old_date, '│ \n\r\t\v\x00'); $new_date = trim($new_date, '│ \n\r\t\v\x00'); $path = trim($path, '│ \n\r\t\v\x00'); $files .= ''; $files .= ''.$old_date.''; $files .= ''.$new_date.''; $files .= ''.$path.''; $file_name = substr($path, strrpos($path, '/') + 1); foreach($conf_locations as $key=>$value) { if (strpos($file_name, $key) !== false) { $link = $value.$file_name; } } $files .= ''; $counter++; } } if(empty($files)) { return ""; } return <<

Version Updates

{$files}

Old Date

New Date

Path

Link



HTML; } function GetAnnouncements() { $feed_url = 'https://info.linuxserver.io/index.xml'; $max_entries = 8; $xml = simplexml_load_string(file_get_contents($feed_url)); $output = ""; $entries = $xml->channel->item; $counter = 1; foreach($entries as $root) { $date = date('Y-m-d', strtotime($root->pubDate)); $output .= ''.htmlspecialchars($date).''; $output .= ''.htmlspecialchars($root->title).''; if($counter >= $max_entries) { break; } $counter++; } return <<

Announcements

{$output}


HTML; } function GetLinks() { return <<

Useful Links



HTML; } function GetGoaccess() { $geodb = ''; $dbip = '/config/geoip2db/dbip-country-lite.mmdb'; $maxmind = '/config/geoip2db/GeoLite2-City.mmdb'; if (file_exists($dbip) and file_exists($maxmind)): $geodb = (filemtime($dbip) > filemtime($maxmind)) ? '--geoip-database='.$dbip : '--geoip-database='.$maxmind; elseif (file_exists($dbip)): $geodb = '--geoip-database='.$dbip; elseif (file_exists($maxmind)): $geodb = '--geoip-database='.$maxmind; endif; $asndb = ''; $asn = '/config/geoip2db/asn.mmdb'; if (file_exists($asn)): $asndb = '--geoip-database='.$asn; endif; $access_log = file_exists("/dashboard/logs") ? "/dashboard/logs/*.log" : "/config/log/nginx/access.log"; $goaccess = shell_exec("cat $access_log | /usr/bin/goaccess -a -o html --config-file=/dashboard/goaccess.conf $geodb $asndb -"); $goaccess = str_replace("Server Statistics", "<title>SWAG Dashboard", $goaccess); $goaccess = str_replace("<h1 class='h-dashboard'>", "<h1>", $goaccess); $goaccess = str_replace("<i class='fa fa-tachometer'></i>", "<img src='/icon.svg' width='32' height='32'> SWAG ", $goaccess); $goaccess = preg_replace("/(<link rel='icon' )(.*?)(>)/", "<link rel='icon' type='image/svg+xml' href='/icon.svg'>", $goaccess); return $goaccess; } function GetCertificate() { $certdate = shell_exec("openssl x509 -in /config/keys/letsencrypt/fullchain.pem -noout -enddate | awk -F '=' '{print \$NF}'"); $certtime = strtotime($certdate); $certdateshort = date('Y-m-d', $certtime ); if (time() < $certtime) { $ssl = '<i class="fas fa-lock"></i> SSL certificate valid until '.$certdateshort; } else { $ssl = '<i class="fas fa-exclamation-circle" title="Check the container logs for more details"></i> SSL certificate expired on '.$certdateshort; } return <<<HTML <div class="pull-right status-div"> <h4> <span class="label label-info" style="display:block"> {$ssl} </span> </h4> </div> HTML; } function GetStats() { $output = shell_exec("if test -f /lsiopy/bin/python3; then /lsiopy/bin/python3 /dashboard/swag-f2b.py; else python3 /dashboard/swag-f2b.py; fi"); $jails = json_decode($output, true); $banned = 0; foreach($jails as $jail){ $banned = $banned + $jail["bans"]; } $output = shell_exec("if test -f /lsiopy/bin/python3; then /lsiopy/bin/python3 /dashboard/swag-proxies.py fast; else python3 /dashboard/swag-proxies.py fast; fi"); $results = json_decode($output); $proxied = 0; $auth = 0; foreach($results as $result => $data){ if (!empty($data->locations)){ $proxied++; if ($data->auth_status == 1) { $auth++; } } } $output = shell_exec("/etc/s6-overlay/s6-rc.d/init-version-checks/run"); $outdated = 0; foreach(explode(PHP_EOL, $output) as $line) { if(str_contains($line, "/config/")) { $outdated++; } } return array("proxied" => "$proxied", "auth" => "$auth", "outdated" => "$outdated", "banned" => "$banned"); } $stats = (isset($_GET['stats']) && $_GET['stats'] == 'true') ? true : false; if($stats) { $page = GetStats(); header("Content-Type: application/json"); echo json_encode($page); } else { $goaccess = GetGoaccess(); $status = GetHeader() . GetProxies() . GetF2B() . GetTemplates() . GetAnnouncements() . GetLinks() . "<div class='wrap-general'>"; $page = str_replace("<div class='wrap-general'>", $status, $goaccess); $ssl = GetCertificate() . "<div class='pull-right hide'>"; $page = str_replace("<div class='pull-right'>", $ssl, $page); echo $page; } ?>