From f550c1349e8f137daa26bf51653ddf2d96ee6bdb Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 14:03:39 +0100 Subject: [PATCH 01/12] improved docker image rebuild speed --- Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index fb015cb..495699e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,4 @@ FROM php:apache -COPY backend-php/ /var/www/html/ -COPY frontend/ /var/www/html/ -COPY docker/start.sh . RUN apt-get update && \ apt-get install -y memcached libmemcached-dev zlib1g-dev libldap2-dev && \ @@ -12,7 +9,11 @@ RUN apt-get update && \ EXPOSE 80/tcp VOLUME /etc/hauk - STOPSIGNAL SIGINT + +COPY docker/start.sh . RUN chmod +x ./start.sh +COPY backend-php/ /var/www/html/ +COPY frontend/ /var/www/html/ + CMD ["./start.sh"] From 6c788e306e6226a3edcd1e4e4899e7ebbeecfb8f Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 14:11:37 +0100 Subject: [PATCH 02/12] Android client sends altitude data --- android/app/src/main/java/info/varden/hauk/Constants.java | 1 + .../main/java/info/varden/hauk/http/LocationUpdatePacket.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/android/app/src/main/java/info/varden/hauk/Constants.java b/android/app/src/main/java/info/varden/hauk/Constants.java index a6909af..651d6e6 100644 --- a/android/app/src/main/java/info/varden/hauk/Constants.java +++ b/android/app/src/main/java/info/varden/hauk/Constants.java @@ -122,6 +122,7 @@ public enum Constants { public static final String PACKET_PARAM_SPEED = "spd"; public static final String PACKET_PARAM_TIMESTAMP = "time"; public static final String PACKET_PARAM_USERNAME = "usr"; + public static final String PACKET_PARAM_ALTITUDE = "alt"; // Packet OK response header. All valid packets start with this line. public static final String PACKET_RESPONSE_OK = "OK"; diff --git a/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java b/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java index 4c571fa..8c80f50 100644 --- a/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java +++ b/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java @@ -48,6 +48,7 @@ public abstract class LocationUpdatePacket extends Packet { super(ctx, session.getServerURL(), session.getConnectionParameters(), Constants.URL_PATH_POST_LOCATION); setParameter(Constants.PACKET_PARAM_SESSION_ID, session.getID()); + // FIXME: Get rid of duplicate code if (session.getDerivableE2EKey() == null) { // If not using end-to-end encryption, send parameters in plain text. setParameter(Constants.PACKET_PARAM_LATITUDE, String.valueOf(location.getLatitude())); @@ -58,6 +59,7 @@ public abstract class LocationUpdatePacket extends Packet { // Not all devices provide these parameters: if (location.hasSpeed()) setParameter(Constants.PACKET_PARAM_SPEED, String.valueOf(location.getSpeed())); if (location.hasAccuracy()) setParameter(Constants.PACKET_PARAM_ACCURACY, String.valueOf(location.getAccuracy())); + if (location.hasAltitude()) setParameter(Constants.PACKET_PARAM_ALTITUDE, String.valueOf(location.getAltitude())); } else { // We're using end-to-end encryption - generate an IV and encrypt all parameters. try { @@ -74,6 +76,7 @@ public abstract class LocationUpdatePacket extends Packet { // Not all devices provide these parameters: if (location.hasSpeed()) setParameter(Constants.PACKET_PARAM_SPEED, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getSpeed()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); if (location.hasAccuracy()) setParameter(Constants.PACKET_PARAM_ACCURACY, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getAccuracy()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); + if (location.hasAltitude()) setParameter(Constants.PACKET_PARAM_ALTITUDE, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getAltitude()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); } catch (Exception e) { Log.e("Error was thrown when encrypting location data", e); //NON-NLS } From 13b6664a27acc7ca07a76435a9b764bf620722c3 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 14:13:48 +0100 Subject: [PATCH 03/12] Backend: push altitude value into points on post --- backend-php/api/post.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend-php/api/post.php b/backend-php/api/post.php index 05048c1..63a7060 100644 --- a/backend-php/api/post.php +++ b/backend-php/api/post.php @@ -21,6 +21,7 @@ $sid = $_POST["sid"]; $session = new Client($memcache, $sid); if (!$session->exists()) die($LANG['session_expired']."\n"); +// FIXME: Get rid of duplicate code if (!$session->isEncrypted()) { // Perform input validation. $lat = floatval($_POST["lat"]); @@ -31,6 +32,7 @@ if (!$session->isEncrypted()) { // Not all devices report speed and accuracy, but if available, report them // too. $speed = isset($_POST["spd"]) ? floatval($_POST["spd"]) : null; + $altitude = isset($_POST["alt"]) ? doubleval($_POST["alt"]) : null; $accuracy = isset($_POST["acc"]) ? floatval($_POST["acc"]) : null; $provider = isset($_POST["prv"]) && $_POST["prv"] == "1" ? 1 : 0; @@ -38,7 +40,7 @@ if (!$session->isEncrypted()) { // and a location list (l). Each entry in the location list contains a // latitude, longitude, timestamp, provider, accuracy and speed, in that // order, as an array. - $session->addPoint([$lat, $lon, $time, $provider, $accuracy, $speed])->save(); + $session->addPoint([$lat, $lon, $time, $provider, $accuracy, $speed, $altitude])->save(); } else { // Input validation cannot be performed for end-to-end encrypted data. @@ -48,6 +50,7 @@ if (!$session->isEncrypted()) { $speed = isset($_POST["spd"]) ? $_POST["spd"] : null; $accuracy = isset($_POST["acc"]) ? $_POST["acc"] : null; $provider = isset($_POST["prv"]) ? $_POST["prv"] : null; + $altitude = isset($_POST["alt"]) ? $_POST["alt"] : null; // End-to-end encrypted connections also have an IV field used to decrypt // the data fields. @@ -55,7 +58,7 @@ if (!$session->isEncrypted()) { $iv = $_POST["iv"]; // The IV field is prepended to the array to send to the client. - $session->addPoint([$iv, $lat, $lon, $time, $provider, $accuracy, $speed])->save(); + $session->addPoint([$iv, $lat, $lon, $time, $provider, $accuracy, $speed, $altitude])->save(); } if ($session->hasExpired()) { From 6b556c13a606a69edf8955082bda0656e8b1d66f Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 14:14:22 +0100 Subject: [PATCH 04/12] Frontend: Read and display altitude data --- frontend/main.js | 41 ++++++++++++++++++++++++++++++++--------- frontend/style.css | 2 +- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/frontend/main.js b/frontend/main.js index 3bbda17..cdd508d 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -684,12 +684,13 @@ function processUpdate(data, init) { var lastPoint = shares[user].points.length > 0 ? shares[user].points[shares[user].points.length - 1] : null; for (var i = 0; i < users[user].length; i++) { - var lat = users[user][i][0]; - var lon = users[user][i][1]; - var time = users[user][i][2]; - var prov = users[user][i][3]; - var acc = users[user][i][4]; - var spd = users[user][i][5]; + var lat = getValueOrNull(users[user][i],0); + var lon = getValueOrNull(users[user][i],1); + var time = getValueOrNull(users[user][i],2); + var prov = getValueOrNull(users[user][i],3); + var acc = getValueOrNull(users[user][i],4); + var spd = getValueOrNull(users[user][i],5); + var alt = getValueOrNull(users[user][i],6); // Default to "Fine" provider for older clients. if (prov === null) prov = LOC_PROVIDER_FINE; @@ -713,11 +714,17 @@ function processUpdate(data, init) { '' + '0.0 ' + VELOCITY_UNIT.unit + - '' + + ' | ' + + '' + + // FIXME: add altitude unit + '0.0 m' + + '' + + '' + '' + '

' + '', - iconAnchor: [33, 18] + // FIXME: hard-coded and dependend on style.css .marker + iconAnchor: [60, 18] }); shares[user].marker = L.marker([lat, lon], {icon: shares[user].icon}).on("click", function() { follow(this.haukUser); @@ -738,7 +745,7 @@ function processUpdate(data, init) { shares[user].circle.setLatLng([lat, lon]); if (acc !== null) shares[user].circle.setRadius(acc); } - shares[user].points.push({lat: lat, lon: lon, line: line, time: time, spd: spd, acc: acc}); + shares[user].points.push({lat: lat, lon: lon, line: line, time: time, spd: spd, acc: acc, alt: alt}); lastPoint = shares[user].points[shares[user].points.length - 1]; } } @@ -781,6 +788,14 @@ function processUpdate(data, init) { vel = velocity(dist, time); eVelocity.textContent = vel.toFixed(1);; } + + // Altitude (If available) + var eAltitude = document.getElementById("altitude-" + shares[user].id); + var alt = 0; + if (lastPoint !== null && lastPoint.alt !== null && eAltitude !== null) { + alt = lastPoint.alt + eAltitude.textContent = alt.toFixed(1) + } // Flag that the first location has been received, for map centering. if (lastPoint !== null && !hasReceivedFirst) { @@ -890,6 +905,14 @@ function processUpdate(data, init) { } } +function getValueOrNull(points,idx) { + var value = null; + if (idx < points.length) { + value = points[idx]; + } + return value; +} + // Calculates the distance between two points on a sphere using the Haversine // algorithm. function distance(from, to) { diff --git a/frontend/style.css b/frontend/style.css index ca776d2..60628f7 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -254,7 +254,7 @@ a:last-child > .store-icon { /* The outer marker div. */ .marker { - width: 66px; + width: 120px; height: 62px; } From 8fd96ba43657cdbac51f2ac5ed3f8315603a127e Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 14:54:34 +0100 Subject: [PATCH 05/12] Added ALTITUDE_UNIT --- backend-php/dynamic.js.php | 1 + backend-php/include/config-sample.php | 4 ++++ backend-php/include/inc.php | 11 +++++++++++ frontend/main.js | 8 ++++---- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/backend-php/dynamic.js.php b/backend-php/dynamic.js.php index 325bead..34a25e4 100644 --- a/backend-php/dynamic.js.php +++ b/backend-php/dynamic.js.php @@ -15,5 +15,6 @@ var MAX_POINTS = ; var VELOCITY_DELTA_TIME = ; var TRAIL_COLOR = ; var VELOCITY_UNIT = ; +var ALTITUDE_UNIT = ; var OFFLINE_TIMEOUT = ; var REQUEST_TIMEOUT = ; diff --git a/backend-php/include/config-sample.php b/backend-php/include/config-sample.php index 9b9d07d..466c398 100644 --- a/backend-php/include/config-sample.php +++ b/backend-php/include/config-sample.php @@ -274,6 +274,10 @@ // KILOMETERS_PER_HOUR, MILES_PER_HOUR, METERS_PER_SECOND "velocity_unit" => KILOMETERS_PER_HOUR, +// The unit of measurement of altitude. Valid are: +// METERS, FEET +"altitude_unit" => METERS, + // The publicly accessible URL to reach Hauk, with trailing slash. "public_url" => 'https://example.com/' diff --git a/backend-php/include/inc.php b/backend-php/include/inc.php index 366a7c2..f423828 100644 --- a/backend-php/include/inc.php +++ b/backend-php/include/inc.php @@ -59,6 +59,16 @@ const METERS_PER_SECOND = array( "mpsMultiplier" => 1, "unit" => "m/s" ); +const METERS = array( + // Absolute distance in meters + "metersMultiplier" => 1, + "unit" => "m" +); +const FEET = array( + // Absolute distance in feet + "metersMultiplier" => 3.280839895, + "unit" => "ft" +); // Load fallback language. include(__DIR__."/lang/en/texts.php"); @@ -149,6 +159,7 @@ const DEFAULTS = array( "v_data_points" => 2, "trail_color" => '#d80037', "velocity_unit" => KILOMETERS_PER_HOUR, + "altitude_unit" => METERS, "public_url" => 'https://example.com/' ); diff --git a/frontend/main.js b/frontend/main.js index cdd508d..ad3fb65 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -716,8 +716,8 @@ function processUpdate(data, init) { VELOCITY_UNIT.unit + ' | ' + '' + - // FIXME: add altitude unit - '0.0 m' + + '0.0 ' + + ALTITUDE_UNIT.unit + '' + '' + '' + @@ -793,8 +793,8 @@ function processUpdate(data, init) { var eAltitude = document.getElementById("altitude-" + shares[user].id); var alt = 0; if (lastPoint !== null && lastPoint.alt !== null && eAltitude !== null) { - alt = lastPoint.alt - eAltitude.textContent = alt.toFixed(1) + alt = lastPoint.alt * ALTITUDE_UNIT.metersMultiplier; + eAltitude.textContent = alt.toFixed(1); } // Flag that the first location has been received, for map centering. From 24750a324bd1bc4e7a36864e84510800ab8a2215 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 15:21:51 +0100 Subject: [PATCH 06/12] hiding all metrics when client is dead --- frontend/main.js | 4 ++-- frontend/style.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/main.js b/frontend/main.js index ad3fb65..7b80010 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -711,11 +711,11 @@ function processUpdate(data, init) { '
' + '

' + '' + - '' + + '' + '0.0 ' + VELOCITY_UNIT.unit + ' | ' + - '' + + '' + '0.0 ' + ALTITUDE_UNIT.unit + '' + diff --git a/frontend/style.css b/frontend/style.css index 60628f7..b799543 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -324,7 +324,7 @@ a:last-child > .store-icon { background-color: rgba(165,0,42,0.5); } -.marker p.dead > span.velocity { +.marker p.dead > span.metric { display: none; } From 9cbd1ccd1f2202383a936701434c23b7cb235ccf Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 16:48:50 +0100 Subject: [PATCH 07/12] Refactored LocationUpdatePackage --- .../hauk/http/LocationUpdatePacket.java | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java b/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java index 8c80f50..21a86f7 100644 --- a/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java +++ b/android/app/src/main/java/info/varden/hauk/http/LocationUpdatePacket.java @@ -5,9 +5,15 @@ import android.location.Location; import android.util.Base64; import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import info.varden.hauk.Constants; import info.varden.hauk.R; @@ -48,39 +54,17 @@ public abstract class LocationUpdatePacket extends Packet { super(ctx, session.getServerURL(), session.getConnectionParameters(), Constants.URL_PATH_POST_LOCATION); setParameter(Constants.PACKET_PARAM_SESSION_ID, session.getID()); - // FIXME: Get rid of duplicate code - if (session.getDerivableE2EKey() == null) { - // If not using end-to-end encryption, send parameters in plain text. - setParameter(Constants.PACKET_PARAM_LATITUDE, String.valueOf(location.getLatitude())); - setParameter(Constants.PACKET_PARAM_LONGITUDE, String.valueOf(location.getLongitude())); - setParameter(Constants.PACKET_PARAM_PROVIDER_ACCURACY, String.valueOf(accuracy.getMode())); - setParameter(Constants.PACKET_PARAM_TIMESTAMP, String.valueOf(System.currentTimeMillis() / (double) TimeUtils.MILLIS_PER_SECOND)); + Cipher cipher = initCipher(session); - // Not all devices provide these parameters: - if (location.hasSpeed()) setParameter(Constants.PACKET_PARAM_SPEED, String.valueOf(location.getSpeed())); - if (location.hasAccuracy()) setParameter(Constants.PACKET_PARAM_ACCURACY, String.valueOf(location.getAccuracy())); - if (location.hasAltitude()) setParameter(Constants.PACKET_PARAM_ALTITUDE, String.valueOf(location.getAltitude())); - } else { - // We're using end-to-end encryption - generate an IV and encrypt all parameters. - try { - Cipher cipher = Cipher.getInstance(Constants.E2E_TRANSFORMATION); - cipher.init(Cipher.ENCRYPT_MODE, session.getDerivableE2EKey().deriveSpec(), new SecureRandom()); - byte[] iv = cipher.getIV(); - setParameter(Constants.PACKET_PARAM_INIT_VECTOR, Base64.encodeToString(iv, Base64.DEFAULT)); + encryptAndSetParameter(Constants.PACKET_PARAM_LATITUDE, location.getLatitude(), cipher); + encryptAndSetParameter(Constants.PACKET_PARAM_LONGITUDE, location.getLongitude(), cipher); + encryptAndSetParameter(Constants.PACKET_PARAM_PROVIDER_ACCURACY, accuracy.getMode(), cipher); + encryptAndSetParameter(Constants.PACKET_PARAM_TIMESTAMP, System.currentTimeMillis() / (double) TimeUtils.MILLIS_PER_SECOND, cipher); - setParameter(Constants.PACKET_PARAM_LATITUDE, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getLatitude()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - setParameter(Constants.PACKET_PARAM_LONGITUDE, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getLongitude()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - setParameter(Constants.PACKET_PARAM_PROVIDER_ACCURACY, Base64.encodeToString(cipher.doFinal(String.valueOf(accuracy.getMode()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - setParameter(Constants.PACKET_PARAM_TIMESTAMP, Base64.encodeToString(cipher.doFinal(String.valueOf(System.currentTimeMillis() / (double) TimeUtils.MILLIS_PER_SECOND).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - - // Not all devices provide these parameters: - if (location.hasSpeed()) setParameter(Constants.PACKET_PARAM_SPEED, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getSpeed()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - if (location.hasAccuracy()) setParameter(Constants.PACKET_PARAM_ACCURACY, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getAccuracy()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - if (location.hasAltitude()) setParameter(Constants.PACKET_PARAM_ALTITUDE, Base64.encodeToString(cipher.doFinal(String.valueOf(location.getAltitude()).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); - } catch (Exception e) { - Log.e("Error was thrown when encrypting location data", e); //NON-NLS - } - } + // Not all devices provide these parameters: + if (location.hasSpeed()) encryptAndSetParameter(Constants.PACKET_PARAM_SPEED, location.getSpeed(), cipher); + if (location.hasAccuracy()) encryptAndSetParameter(Constants.PACKET_PARAM_ACCURACY, location.getAccuracy(), cipher); + if (location.hasAltitude()) encryptAndSetParameter(Constants.PACKET_PARAM_ALTITUDE, location.getAltitude(), cipher); } @SuppressWarnings("DesignForExtension") @@ -116,4 +100,33 @@ public abstract class LocationUpdatePacket extends Packet { throw new ServerException(err.toString()); } } + + private Cipher initCipher(Session session) { + Cipher cipher = null; + if (session.getDerivableE2EKey() != null) { + try { + cipher = Cipher.getInstance(Constants.E2E_TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, session.getDerivableE2EKey().deriveSpec(), new SecureRandom()); + byte[] iv = cipher.getIV(); + setParameter(Constants.PACKET_PARAM_INIT_VECTOR, Base64.encodeToString(iv, Base64.DEFAULT)); + } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException exception) { + Log.e("Error was thrown while initializing E2E encryption", exception); //NON-NLS + } + } + return cipher; + } + + private void encryptAndSetParameter(String key, V value, Cipher cipher) { + if (cipher != null) { + // We're using end-to-end encryption - generate an IV and encrypt all parameters. + try { + setParameter(key, Base64.encodeToString(cipher.doFinal(String.valueOf(value).getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT)); + } catch (BadPaddingException | IllegalBlockSizeException exception) { + Log.e("Error was thrown while encrypting location data", exception); //NON-NLS + } + } else { + // If not using end-to-end encryption, send parameters in plain text. + setParameter(key, String.valueOf(value)); + } + } } From b5dad6ebe20f30deceae49d5d1dacb39841473e9 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Sat, 27 Mar 2021 17:41:33 +0100 Subject: [PATCH 08/12] Refactored post.php --- backend-php/api/post.php | 51 ++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/backend-php/api/post.php b/backend-php/api/post.php index 63a7060..562e6e9 100644 --- a/backend-php/api/post.php +++ b/backend-php/api/post.php @@ -21,48 +21,37 @@ $sid = $_POST["sid"]; $session = new Client($memcache, $sid); if (!$session->exists()) die($LANG['session_expired']."\n"); -// FIXME: Get rid of duplicate code -if (!$session->isEncrypted()) { - // Perform input validation. - $lat = floatval($_POST["lat"]); - $lon = floatval($_POST["lon"]); - $time = floatval($_POST["time"]); - if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) die($LANG['location_invalid']."\n"); +$lat = $_POST["lat"]; +$lon = $_POST["lon"]; +$time = $_POST["time"]; +$speed = isset($_POST["spd"]) ? $_POST["spd"] : null; +$altitude = isset($_POST["alt"]) ? $_POST["alt"] : null; +$accuracy = isset($_POST["acc"]) ? $_POST["acc"] : null; +$provider = isset($_POST["prv"]) ? $_POST["prv"] : null; - // Not all devices report speed and accuracy, but if available, report them - // too. - $speed = isset($_POST["spd"]) ? floatval($_POST["spd"]) : null; - $altitude = isset($_POST["alt"]) ? doubleval($_POST["alt"]) : null; - $accuracy = isset($_POST["acc"]) ? floatval($_POST["acc"]) : null; - $provider = isset($_POST["prv"]) && $_POST["prv"] == "1" ? 1 : 0; - - // The location data object contains the sharing interval (i), duration (d) - // and a location list (l). Each entry in the location list contains a - // latitude, longitude, timestamp, provider, accuracy and speed, in that - // order, as an array. - $session->addPoint([$lat, $lon, $time, $provider, $accuracy, $speed, $altitude])->save(); - -} else { - // Input validation cannot be performed for end-to-end encrypted data. - $lat = $_POST["lat"]; - $lon = $_POST["lon"]; - $time = $_POST["time"]; - $speed = isset($_POST["spd"]) ? $_POST["spd"] : null; - $accuracy = isset($_POST["acc"]) ? $_POST["acc"] : null; - $provider = isset($_POST["prv"]) ? $_POST["prv"] : null; - $altitude = isset($_POST["alt"]) ? $_POST["alt"] : null; +// The location data object contains the sharing interval (i), duration (d) +// and a location list (l). Each entry in the location list contains a +// latitude, longitude, timestamp, provider, accuracy and speed, in that +// order, as an array. +$point = [$lat, $lon, $time, $provider, $accuracy, $speed, $altitude]; +if ($session->isEncrypted()) { // End-to-end encrypted connections also have an IV field used to decrypt // the data fields. requirePOST("iv"); $iv = $_POST["iv"]; // The IV field is prepended to the array to send to the client. - $session->addPoint([$iv, $lat, $lon, $time, $provider, $accuracy, $speed, $altitude])->save(); + array_unshift($point , $iv); +} else { + // Perform input validation + if (floatval($lat) < -90 || floatval($lat) > 90 || floatval($lon) < -180 || floatval($lon) > 180) die($LANG['location_invalid']."\n"); } +$session->addPoint($point)->save(); + if ($session->hasExpired()) { echo $LANG['session_expired']."\n"; } else { echo "OK\n".getConfig("public_url")."?%s\n".implode(",", $session->getTargetIDs())."\n"; -} +} \ No newline at end of file From 082da40d57a952f573a7f56bd721ee9986768c2a Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Fri, 2 Apr 2021 00:40:20 +0200 Subject: [PATCH 09/12] Moved altitude to its own line and added labels --- frontend/main.js | 15 ++++++++------- frontend/style.css | 23 ++++++++++++++++++++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/frontend/main.js b/frontend/main.js index 7b80010..cf8b08c 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -712,19 +712,20 @@ function processUpdate(data, init) { '

' + '' + '' + - '0.0 ' + - VELOCITY_UNIT.unit + - ' | ' + - '' + - '0.0 ' + - ALTITUDE_UNIT.unit + + 'vel:' + + '0.0 ' + + VELOCITY_UNIT.unit + '' + + '
' + + 'alt:' + + '0.0 ' + + ALTITUDE_UNIT.unit + '' + '
' + '' + '' + '

' + '', // FIXME: hard-coded and dependend on style.css .marker - iconAnchor: [60, 18] + iconAnchor: [48, 18] }); shares[user].marker = L.marker([lat, lon], {icon: shares[user].icon}).on("click", function() { follow(this.haukUser); diff --git a/frontend/style.css b/frontend/style.css index b799543..d7521b9 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -254,7 +254,7 @@ a:last-child > .store-icon { /* The outer marker div. */ .marker { - width: 120px; + width: 96px; height: 62px; } @@ -302,8 +302,8 @@ a:last-child > .store-icon { width: 100%; border-radius: 15px; text-align: center; - padding: 2px 0; - line-height: 100%; + padding: 5px 0 5px; + line-height: 125%; font-family: sans-serif; overflow: hidden; white-space: nowrap; @@ -333,3 +333,20 @@ a:last-child > .store-icon { background: none; border: none; } + +.metric-label { + display:inline-block; + width: 30%; + text-align:right; + vertical-align: bottom; + padding-right: 0.5em; +} + +.metric-value { + display:inline-block; + width: 70%; + text-align: left; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: bottom; +} From 27a19597a982c955eebfe3ee07fc719c8cb72c95 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Fri, 2 Apr 2021 12:04:34 +0200 Subject: [PATCH 10/12] Displaying metrics is optional --- backend-php/dynamic.js.php | 2 ++ backend-php/include/config-sample.php | 6 ++++++ backend-php/include/inc.php | 2 ++ frontend/main.js | 4 +++- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/backend-php/dynamic.js.php b/backend-php/dynamic.js.php index 34a25e4..47e2867 100644 --- a/backend-php/dynamic.js.php +++ b/backend-php/dynamic.js.php @@ -16,5 +16,7 @@ var VELOCITY_DELTA_TIME = var TRAIL_COLOR = ; var VELOCITY_UNIT = ; var ALTITUDE_UNIT = ; +var SHOW_VELOCITY = ; +var SHOW_ALTITUDE_AMSL = ; var OFFLINE_TIMEOUT = ; var REQUEST_TIMEOUT = ; diff --git a/backend-php/include/config-sample.php b/backend-php/include/config-sample.php index 466c398..9186369 100644 --- a/backend-php/include/config-sample.php +++ b/backend-php/include/config-sample.php @@ -278,6 +278,12 @@ // METERS, FEET "altitude_unit" => METERS, +// Display velocity below marker +"show_velocity" => true, + +// Display altitude AMSL below marker +"show_altitude_amsl"=> true, + // The publicly accessible URL to reach Hauk, with trailing slash. "public_url" => 'https://example.com/' diff --git a/backend-php/include/inc.php b/backend-php/include/inc.php index f423828..9465ead 100644 --- a/backend-php/include/inc.php +++ b/backend-php/include/inc.php @@ -160,6 +160,8 @@ const DEFAULTS = array( "trail_color" => '#d80037', "velocity_unit" => KILOMETERS_PER_HOUR, "altitude_unit" => METERS, + "show_velocity" => true, + "show_altitude_amsl" => true, "public_url" => 'https://example.com/' ); diff --git a/frontend/main.js b/frontend/main.js index cf8b08c..394d33c 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -711,11 +711,13 @@ function processUpdate(data, init) { '
' + '

' + '' + - '' + + '' + 'vel:' + '0.0 ' + VELOCITY_UNIT.unit + '' + '
' + + '
' + + '' + 'alt:' + '0.0 ' + ALTITUDE_UNIT.unit + '' + From 4ae423a407d20c82052aa05dfe39dec198063196 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Fri, 2 Apr 2021 12:34:19 +0200 Subject: [PATCH 11/12] Hiding altitude if value is null --- frontend/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/main.js b/frontend/main.js index 394d33c..8cc71fa 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -717,7 +717,7 @@ function processUpdate(data, init) { VELOCITY_UNIT.unit + '' + '
' + '
' + - '' + + '' + 'alt:' + '0.0 ' + ALTITUDE_UNIT.unit + '' + @@ -795,9 +795,13 @@ function processUpdate(data, init) { // Altitude (If available) var eAltitude = document.getElementById("altitude-" + shares[user].id); var alt = 0; + var eAltitudeContainer = document.getElementById("altitude-container-" + shares[user].id); if (lastPoint !== null && lastPoint.alt !== null && eAltitude !== null) { alt = lastPoint.alt * ALTITUDE_UNIT.metersMultiplier; eAltitude.textContent = alt.toFixed(1); + eAltitudeContainer.classList.remove("hidden"); + } else { + eAltitudeContainer.classList.add("hidden"); } // Flag that the first location has been received, for map centering. From 33e19cb886e85532011232bde724b84660be4022 Mon Sep 17 00:00:00 2001 From: tuffnerdstuff Date: Fri, 2 Apr 2021 13:19:46 +0200 Subject: [PATCH 12/12] Only unhide altitude if config allows it --- frontend/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/main.js b/frontend/main.js index 8cc71fa..e8ad30a 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -799,7 +799,9 @@ function processUpdate(data, init) { if (lastPoint !== null && lastPoint.alt !== null && eAltitude !== null) { alt = lastPoint.alt * ALTITUDE_UNIT.metersMultiplier; eAltitude.textContent = alt.toFixed(1); - eAltitudeContainer.classList.remove("hidden"); + if (SHOW_ALTITUDE_AMSL) { + eAltitudeContainer.classList.remove("hidden"); + } } else { eAltitudeContainer.classList.add("hidden"); }