From 899731f084900800a065d8167bef91aed0e3c1ee Mon Sep 17 00:00:00 2001 From: ioClarity Date: Mon, 27 Jul 2020 22:06:32 -0700 Subject: [PATCH] Mitigated possible DoS Vulnerability --- .gitignore | 1 + DASHBOARD.README | 22 +++++ dashboardV2/bin/getJson.php | 144 +++++++++++++++++++++++++++++ dashboardV2/index.php | 41 +++++--- dashboardV2/jsonData/lastHeard.php | 31 ------- dashboardV2/jsonData/modules.php | 56 ----------- dashboardV2/jsonData/proc.php | 24 ----- 7 files changed, 194 insertions(+), 125 deletions(-) create mode 100644 dashboardV2/bin/getJson.php delete mode 100644 dashboardV2/jsonData/lastHeard.php delete mode 100644 dashboardV2/jsonData/modules.php delete mode 100644 dashboardV2/jsonData/proc.php diff --git a/.gitignore b/.gitignore index c7c38ad..e170dee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ qnvoice qnrelay qnmodem My_Hosts.txt +dashboardV2/jsonData/*.json diff --git a/DASHBOARD.README b/DASHBOARD.README index bc9be75..d9f689c 100644 --- a/DASHBOARD.README +++ b/DASHBOARD.README @@ -27,3 +27,25 @@ will want to use a hardened server, like apache, and a different index.php file. Please note that if you are tryping in a URCALL when the webpage is refreshing, the entry field will loose focus and you'll have to try again. + + + #### DASHBOARD V2 #### + +A new responsive dashboard built on the Bootstrap 4.5 framework has been +added. If you have configured the dashboard with the commands above you can +access the new dashboard by appending "/dashboardV2" to the URL. For example +http://.local/dashboardV2 + +Notes: +The responsive dashboard currently has the following features + * Page does not have to reload to refresh its data solving the URCall focus issue + * Dashboard refresh is suggested to be set at 10 seconds. Any value less than 8 will + have no effect. + * Mobile design friendly. On smaller screens some columns in the tables will be + hidden, however, simply rotate your mobile device to landscape view and they + should appear + * QnRemote section (aka URCall section) has improved design for mobile device use + +Future improvements will be made to + * The layout to respect order of the dash_show_order configuration item + * Misc performance enhancements diff --git a/dashboardV2/bin/getJson.php b/dashboardV2/bin/getJson.php new file mode 100644 index 0000000..ccb2e15 --- /dev/null +++ b/dashboardV2/bin/getJson.php @@ -0,0 +1,144 @@ + 8 ) +{ + # OpenDatabase + $dbname = $cfgdir.'/qn.db'; + $db = new SQLite3($dbname, SQLITE3_OPEN_READONLY); + + # Only proccess if defined in show list + if( in_array("LH", $showlist) ) { + $jsonArray = []; + $ss = 'SELECT callsign,sfx,message,module,reflector,maidenhead,latitude,longitude,strftime("%s","now")-lasttime as lastTime FROM LHEARD ORDER BY lastTime LIMIT '.GetCFGValue('dash_lastheard_count').' '; + if ($stmnt = $db->prepare($ss)) { + if ($result = $stmnt->execute()) { + while ($row = $result->FetchArray(SQLITE3_ASSOC)) { + //transform the lastTimeHeard to a printable string + $row['lastTime'] = SecToString($row['lastTime']); + $row['maidenheadProcessed'] = Maidenhead($row['maidenhead'], $row['latitude'], $row['longitude']); + $row['callsignProcessed'] = MyAndSfxToQrz($row['callsign'], $row['sfx']); + $jsonArray[] = $row; + } + $result->finalize(); + } + $stmnt->close(); + } + + # Write the lastHeard JSON file + $lhJsonFile = fopen("../jsonData/lastHeard.json", "w"); + fwrite($lhJsonFile, json_encode($jsonArray)); + fclose($lhJsonFile); + } else { echo "Section disabled"; + $lhJsonFile = fopen("../jsonData/lastHeard.json", "w"); + fwrite($lhJsonFile, "{ }\n"); + fclose($lhJsonFile); + } + + + # Only proccess if defined in show list + if( in_array("MO", $showlist) ) { + $jsonArray = []; + foreach (array('a', 'b', 'c') as $mod) { + $linkstatus = 'Unlinked'; + $address = ''; + $ctime = ''; + $module = 'module_'.$mod; + if (array_key_exists($module, $cfg)) { + $freq = 0.0; + if (array_key_exists($module.'_tx_frequency', $cfg)) { + $freq = $cfg[$module.'_tx_frequency']; + } + else if (array_key_exists($module.'_frequency', $cfg)) { + $freq = $cfg[$module.'_frequency']; + } + $ss = 'SELECT ip_address,to_callsign,to_mod,strftime("%s","now")-linked_time as linkedTime FROM LINKSTATUS WHERE from_mod=' . "'" . strtoupper($mod) . "';"; + if ($stmnt = $db->prepare($ss)) { + if ($result = $stmnt->execute()) { + if ($row = $result->FetchArray(SQLITE3_ASSOC)) { + $row['linkedTime'] = SecToString(intval($row['linkedTime'])); + $row['module'] = strtoupper($mod); + $row['modem'] = $cfg[$module]; + $row['freq'] = $freq; + $row['link'] = $row['to_callsign']." ".$row['to_mod']; + $jsonArray[] = $row; + } else { + $jsonArray[] = array('linkedTime' => '', + 'module' =>strtoupper($mod), + 'modem' => $cfg[$module], + 'freq' => $freq, + 'link' => 'Unlinked', + 'ip_address' => '', + 'to_callsign' => '', + 'to_mod' => ''); + } + $result->finalize(); + } + $stmnt->close(); + } + } + } + $modJsonFile = fopen("../jsonData/modules.json", "w"); + fwrite($modJsonFile, json_encode($jsonArray)); + fclose($modJsonFile); + } else { + $modJsonFile = fopen("../jsonData/modules.json", "w"); + fwrite($modJsonFile, "{ }\n"); + fclose($modJsonFile); + } + + # Close database it is not needed anymore + $db->Close(); + + + # Only proccess if defined in show list + if( in_array("PS", $showlist) ) { + $jsonArray = []; + $lines = explode("\n", `ps -eo user,pid,pcpu,size,cmd | grep -e qngateway -e qnlink -e qndtmf -e qndvap -e qnitap -e qnrelay -e qndvrptr -e qnmodem -e MMDVMHost | grep -v grep`); + foreach ($lines as $line) { + $items = preg_split ('/\s+/', $line, 5); + if( isset( $items[1] ) ) { + $jsonArray[] = array('user' => $items[0], + 'pid' => $items[1], + 'pcpu' => $items[2], + 'size' => $items[3], + 'cmd' => $items[4]); + } + } + $psJsonFile = fopen("../jsonData/ps.json", "w"); + if ($jsonArray) { + fwrite($psJsonFile, json_encode($jsonArray)); + } else { + fwrite($psJsonFile, "{ }\n"); + } + fclose($psJsonFile); + } else { + # Section is disabled, replace with blank JSON file + $psJsonFile = fopen("../jsonData/ps.json", "w"); + fwrite($psJsonFile, "{ }\n"); + fclose($psJsonFile); + } + + # Update last run time + `touch $lastRunFile`; +} + +# If the jsonFile is in the URL lets get the file +if( isset($_GET['jsonFile']) ) +{ + if( $_GET['jsonFile'] == "lastHeard" ) + readfile("../jsonData/lastHeard.json"); + else if( $_GET['jsonFile'] == "modules" ) + readfile("../jsonData/modules.json"); + else if( $_GET['jsonFile'] == "ps" ) + readfile("../jsonData/ps.json"); +} +?> + diff --git a/dashboardV2/index.php b/dashboardV2/index.php index 6a02118..d80c4b5 100644 --- a/dashboardV2/index.php +++ b/dashboardV2/index.php @@ -1,23 +1,36 @@ $strlen) return false; + return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; + } + + if ( !( endsWith($_SERVER['REQUEST_URI'], "/index.php") || (endsWith($_SERVER['REQUEST_URI'], "/") ) ) ) + { + header("Location: dashboardV2/"); + } + # Load functions and read config file include 'init.php'; ?> - QnetGateway Dashboard V2 - - + + - - + +