Merge branch 'master' into docker

This commit is contained in:
adolfintel 2019-01-31 12:32:50 +01:00
commit 94574b5f29
10 changed files with 87 additions and 38 deletions

3
.gitignore vendored
View file

@ -1,2 +1 @@
ugly.bat telemetry/idObfuscation_salt.php
wishlist.txt

13
doc.md
View file

@ -1,7 +1,7 @@
# HTML5 Speedtest # HTML5 Speedtest
> by Federico Dossena > by Federico Dossena
> Version 4.7 > Version 4.7.1
> [https://github.com/adolfintel/speedtest/](https://github.com/adolfintel/speedtest/) > [https://github.com/adolfintel/speedtest/](https://github.com/adolfintel/speedtest/)
@ -148,7 +148,7 @@ The response from the worker is a JSON string containing these entries:
* __dlProgress__: the progress of the download test as a number between 0 and 1 * __dlProgress__: the progress of the download test as a number between 0 and 1
* __ulProgress__: the progress of the upload test as a number between 0 and 1 * __ulProgress__: the progress of the upload test as a number between 0 and 1
* __pingProgress__: the progress of the ping+jitter test as a number between 0 and 1 * __pingProgress__: the progress of the ping+jitter test as a number between 0 and 1
* __testId__: when telemetry is active, this is the ID of the test as an integer. This string is 'noID' until the test is finished (testState 4). This ID is used for results sharing * __testId__: when telemetry is active, this is the ID of the test in the database. This string is null until the test is finished (testState 4), or if telemetry encounters an error. This ID is used for results sharing
### Starting the test ### Starting the test
To start the test with the default settings, which is usually the best choice, send the start command to the worker: To start the test with the default settings, which is usually the best choice, send the start command to the worker:
@ -381,6 +381,15 @@ This feature requires Telemetry to be enabled, and FreeType2 must be installed i
__Important:__ This feature relies on PHP functions `imagefttext` and `imageftbbox` that are well known for being problematic. The most common problem is that they can't find the font files and therefore nothing is drawn. This problem is metioned [here](http://php.net/manual/en/function.imagefttext.php) and was experienced by a lot of users. __Important:__ This feature relies on PHP functions `imagefttext` and `imageftbbox` that are well known for being problematic. The most common problem is that they can't find the font files and therefore nothing is drawn. This problem is metioned [here](http://php.net/manual/en/function.imagefttext.php) and was experienced by a lot of users.
#### Obfuscated Test IDs
By default, the telemetry generates a progressive ID for each test. Even if no sensitive information is leaked, you might not want users to be able to guess other test IDs. To avoid this, you can turn on ID obfuscation, which turns IDs into a reversible hash, much like YouTube video IDs.
To enable this feature, edit `telemetry_settings.php` and set `enable_id_obfuscation` to true.
From now on, all test IDs will be obfuscated using a unique salt. The IDs in the database are still progressive, but users will only know their obfuscated versions and won't be able to easily guess other IDs.
__Important:__ Make sure PHP is allowed to write to the `telemetry` folder. The salt will be stored in a file called `idObfuscation_salt.php`. This file is like a private key, don't lose it or you won't be able to deobfuscate IDs anymore!
### Seeing the results ### Seeing the results
A basic front-end for visualizing and searching tests by ID is available in `telemetry/stats.php`. A basic front-end for visualizing and searching tests by ID is available in `telemetry/stats.php`.

View file

@ -190,8 +190,8 @@ function startStop(){
if(status==4){ if(status==4){
//if testId is present, show sharing panel, otherwise do nothing //if testId is present, show sharing panel, otherwise do nothing
try{ try{
var testId=Number(data.testId); var testId=data.testId;
if(!isNaN(testId)){ if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId; var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL; I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL; I("resultsURL").value=shareURL;

View file

@ -52,6 +52,8 @@ $WATERMARK_TEXT="HTML5 Speedtest";
$id=$_GET["id"]; $id=$_GET["id"];
include_once('../telemetry/telemetry_settings.php'); include_once('../telemetry/telemetry_settings.php');
require '../telemetry/idObfuscation.php';
if($enable_id_obfuscation) $id=deobfuscateId($id);
$conn=null; $q=null; $conn=null; $q=null;
$ispinfo=null; $dl=null; $ul=null; $ping=null; $jit=null; $ispinfo=null; $dl=null; $ul=null; $ping=null; $jit=null;
if($db_type=="mysql"){ if($db_type=="mysql"){

View file

@ -1,5 +1,5 @@
/* /*
HTML5 Speedtest v4.7 HTML5 Speedtest v4.7.1
by Federico Dossena by Federico Dossena
https://github.com/adolfintel/speedtest/ https://github.com/adolfintel/speedtest/
GNU LGPLv3 License GNU LGPLv3 License
@ -15,7 +15,7 @@ var clientIp = ""; // client's IP address as reported by getIP.php
var dlProgress = 0; //progress of download test 0-1 var dlProgress = 0; //progress of download test 0-1
var ulProgress = 0; //progress of upload test 0-1 var ulProgress = 0; //progress of upload test 0-1
var pingProgress = 0; //progress of ping+jitter test 0-1 var pingProgress = 0; //progress of ping+jitter test 0-1
var testId = "noID"; //test ID (sent back by telemetry if used, the string 'noID' otherwise) var testId = null; //test ID (sent back by telemetry if used, null otherwise)
var log = ""; //telemetry log var log = ""; //telemetry log
function tlog(s) { function tlog(s) {
@ -173,7 +173,7 @@ this.addEventListener("message", function(e) {
if (settings.telemetry_level > 0) if (settings.telemetry_level > 0)
sendTelemetry(function(id) { sendTelemetry(function(id) {
testStatus = 4; testStatus = 4;
if (id != -1) testId = id; if (id != null) testId = id;
}); });
else testStatus = 4; else testStatus = 4;
return; return;
@ -460,21 +460,11 @@ function ulTest(done) {
} }
if (ie11workaround) { if (ie11workaround) {
// IE11 workarond: xhr.upload does not work properly, therefore we send a bunch of small 256k requests and use the onload event as progress. This is not precise, especially on fast connections // IE11 workarond: xhr.upload does not work properly, therefore we send a bunch of small 256k requests and use the onload event as progress. This is not precise, especially on fast connections
xhr[i].onload = function() { xhr[i].onload = xhr[i].onerror = function() {
tverb("ul stream progress event (ie11wa)"); tverb("ul stream progress event (ie11wa)");
totLoaded += reqsmall.size; totLoaded += reqsmall.size;
testStream(i, 0); testStream(i, 0);
}; };
xhr[i].onerror = function() {
// error, abort
tverb("ul stream failed (ie11wa)");
if (settings.xhr_ignoreErrors === 0) failed = true; //abort
try {
xhr[i].abort();
} catch (e) {}
delete xhr[i];
if (settings.xhr_ignoreErrors === 1) testStream(i, 0); //restart stream
};
xhr[i].open("POST", settings.url_ul + url_sep(settings.url_ul) + "r=" + Math.random(), true); // random string to prevent caching xhr[i].open("POST", settings.url_ul + url_sep(settings.url_ul) + "r=" + Math.random(), true); // random string to prevent caching
xhr[i].setRequestHeader("Content-Encoding", "identity"); // disable compression (some browsers may refuse it, but data is incompressible anyway) xhr[i].setRequestHeader("Content-Encoding", "identity"); // disable compression (some browsers may refuse it, but data is incompressible anyway)
xhr[i].send(reqsmall); xhr[i].send(reqsmall);
@ -662,15 +652,14 @@ function sendTelemetry(done) {
var parts = xhr.responseText.split(" "); var parts = xhr.responseText.split(" ");
if (parts[0] == "id") { if (parts[0] == "id") {
try { try {
var id = Number(parts[1]); var id = parts[1];
if (!isNaN(id)) done(id); done(id);
else done(-1);
} catch (e) { } catch (e) {
done(-1); done(null);
} }
} else done(-1); } else done(null);
} catch (e) { } catch (e) {
done(-1); done(null);
} }
}; };
xhr.onerror = function() { xhr.onerror = function() {

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
<?php
function getObfuscationSalt(){
$saltFile=dirname(__FILE__)."/idObfuscation_salt.php";
if(file_exists($saltFile)){
require $saltFile;
}else{
$bytes=openssl_random_pseudo_bytes(4);
$sf=fopen($saltFile,"w");
fwrite($sf,chr(60)."?php\n");
fwrite($sf,'$OBFUSCATION_SALT=0x'.bin2hex($bytes).";\n");
fwrite($sf,"?".chr(62));
fclose($sf);
require $saltFile;
}
return isset($OBFUSCATION_SALT)?$OBFUSCATION_SALT:0;
}
/*
This is a simple reversible hash function I made for encoding and decoding test IDs.
It is not cryptographically secure, don't use it to hash passwords or something!
*/
function obfdeobf($id){
$salt=getObfuscationSalt()&0xFFFFFFFF;
$id=$id&0xFFFFFFFF;
for($i=0;$i<16;$i++){
$id=$id^$salt;
$id=(($id>>1)&0xFFFFFFFF)|(($id&0x00000001)<<31);
$salt=(($salt<<1)&0xFFFFFFFF)|(($salt&0xA0000000)>>31);
}
return $id;
}
function obfuscateId($id){
return base_convert(obfdeobf($id),10,36);
}
function deobfuscateId($id){
return obfdeobf(base_convert($id,36,10));
}
//IMPORTANT: DO NOT ADD ANYTHING BELOW THE PHP CLOSING TAG, NOT EVEN EMPTY LINES!
?>

View file

@ -2,6 +2,9 @@
session_start(); session_start();
error_reporting(0); error_reporting(0);
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -54,6 +57,7 @@ header('Content-Type: text/html; charset=utf-8');
<h1>HTML5 Speedtest - Stats</h1> <h1>HTML5 Speedtest - Stats</h1>
<?php <?php
include_once("telemetry_settings.php"); include_once("telemetry_settings.php");
require "idObfuscation.php";
if($stats_password=="PASSWORD"){ if($stats_password=="PASSWORD"){
?> ?>
Please set $stats_password in telemetry_settings.php to enable access. Please set $stats_password in telemetry_settings.php to enable access.
@ -61,7 +65,7 @@ if($stats_password=="PASSWORD"){
}else if($_SESSION["logged"]===true){ }else if($_SESSION["logged"]===true){
if($_GET["op"]=="logout"){ if($_GET["op"]=="logout"){
$_SESSION["logged"]=false; $_SESSION["logged"]=false;
?><script type="text/javascript">window.location.search=""</script><?php ?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
}else{ }else{
$conn=null; $conn=null;
if($db_type=="mysql"){ if($db_type=="mysql"){
@ -76,20 +80,22 @@ if($stats_password=="PASSWORD"){
$conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password"); $conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password");
}else die(); }else die();
?> ?>
<form action="stats.php?op=logout" method="POST"><input type="submit" value="Logout" /></form> <form action="stats.php" method="GET"><input type="hidden" name="op" value="logout" /><input type="submit" value="Logout" /></form>
<form action="stats.php?op=id" method="POST"> <form action="stats.php" method="GET">
<h3>Search test results</h6> <h3>Search test results</h6>
<input type="hidden" name="op" value="id" />
<input type="text" name="id" id="id" placeholder="Test ID" value=""/> <input type="text" name="id" id="id" placeholder="Test ID" value=""/>
<input type="submit" value="Find" /> <input type="submit" value="Find" />
<input type="submit" onclick="document.getElementById('id').value=''" value="Show last 100 tests" /> <input type="submit" onclick="document.getElementById('id').value=''" value="Show last 100 tests" />
</form> </form>
<?php <?php
$q=null; $q=null;
if($_GET["op"]=="id"&&!empty($_POST["id"])){ if($_GET["op"]=="id"&&!empty($_GET["id"])){
$id=$_POST["id"]; $id=$_GET["id"];
if($enable_id_obfuscation) $id=deobfuscateId($id);
if($db_type=="mysql"){ if($db_type=="mysql"){
$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?"); $q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?");
$q->bind_param("i",$_POST["id"]); $q->bind_param("i",$id);
$q->execute(); $q->execute();
$q->store_result(); $q->store_result();
$q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra); $q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra);
@ -129,7 +135,7 @@ if($stats_password=="PASSWORD"){
}else die(); }else die();
?> ?>
<table> <table>
<tr><th>Test ID</th><td><?=htmlspecialchars($id, ENT_HTML5, 'UTF-8') ?></td></tr> <tr><th>Test ID</th><td><?=htmlspecialchars(($enable_id_obfuscation?obfuscateId($id):$id), ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Date and time</th><td><?=htmlspecialchars($timestamp, ENT_HTML5, 'UTF-8') ?></td></tr> <tr><th>Date and time</th><td><?=htmlspecialchars($timestamp, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>IP and ISP Info</th><td><?=$ip ?><br/><?=htmlspecialchars($ispinfo, ENT_HTML5, 'UTF-8') ?></td></tr> <tr><th>IP and ISP Info</th><td><?=$ip ?><br/><?=htmlspecialchars($ispinfo, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>User agent and locale</th><td><?=$ua ?><br/><?=htmlspecialchars($lang, ENT_HTML5, 'UTF-8') ?></td></tr> <tr><th>User agent and locale</th><td><?=$ua ?><br/><?=htmlspecialchars($lang, ENT_HTML5, 'UTF-8') ?></td></tr>
@ -148,7 +154,7 @@ if($stats_password=="PASSWORD"){
}else{ }else{
if($_GET["op"]=="login"&&$_POST["password"]===$stats_password){ if($_GET["op"]=="login"&&$_POST["password"]===$stats_password){
$_SESSION["logged"]=true; $_SESSION["logged"]=true;
?><script type="text/javascript">window.location.search=""</script><?php ?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
}else{ }else{
?> ?>
<form action="stats.php?op=login" method="POST"> <form action="stats.php?op=login" method="POST">

View file

@ -1,5 +1,6 @@
<?php <?php
include_once('telemetry_settings.php'); include_once('telemetry_settings.php');
require 'idObfuscation.php';
$ip=($_SERVER['REMOTE_ADDR']); $ip=($_SERVER['REMOTE_ADDR']);
$ispinfo=($_POST["ispinfo"]); $ispinfo=($_POST["ispinfo"]);
@ -18,7 +19,8 @@ if($db_type=="mysql"){
$stmt->bind_param("ssssssssss",$ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log) or die("3"); $stmt->bind_param("ssssssssss",$ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log) or die("3");
$stmt->execute() or die("4"); $stmt->execute() or die("4");
$stmt->close() or die("5"); $stmt->close() or die("5");
echo "id ".$conn->insert_id; $id=$conn->insert_id;
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn->close() or die("6"); $conn->close() or die("6");
}elseif($db_type=="sqlite"){ }elseif($db_type=="sqlite"){
@ -41,7 +43,8 @@ if($db_type=="mysql"){
"); ");
$stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2"); $stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2");
$stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3"); $stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3");
echo "id ".$conn->lastInsertId(); $id=$conn->lastInsertId();
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn = null; $conn = null;
}elseif($db_type=="postgresql"){ }elseif($db_type=="postgresql"){
// Prepare connection parameters for db connection // Prepare connection parameters for db connection
@ -53,7 +56,8 @@ if($db_type=="mysql"){
$conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password") or die("1"); $conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password") or die("1");
$stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2"); $stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2");
$stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3"); $stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3");
echo "id ".$conn->lastInsertId(); $id=$conn->lastInsertId();
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn = null; $conn = null;
} }
else die("-1"); else die("-1");

View file

@ -2,6 +2,7 @@
$db_type="mysql"; //Type of db: "mysql", "sqlite" or "postgresql" $db_type="mysql"; //Type of db: "mysql", "sqlite" or "postgresql"
$stats_password="PASSWORD"; //password to login to stats.php. Change this!!! $stats_password="PASSWORD"; //password to login to stats.php. Change this!!!
$enable_id_obfuscation=false; //if set to true, test IDs will be obfuscated to prevent users from guessing URLs of other tests
// Sqlite3 settings // Sqlite3 settings
$Sqlite_db_file = "../../telemetry.sql"; $Sqlite_db_file = "../../telemetry.sql";