From 2dd0beb62f425f8086ff4538c0c3ceb497fad8da Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 1 Mar 2023 03:01:07 +0100 Subject: [PATCH] DAQ: Mask `PASSKEY` variable coming from HTTP, emitted by Ecowitt --- CHANGES.rst | 1 + kotori/io/protocol/http.py | 10 ++++- test/test_ecowitt.py | 88 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 test/test_ecowitt.py diff --git a/CHANGES.rst b/CHANGES.rst index 340b0248..19f5792e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ in progress =========== - CI: Update to Grafana 9.3.0 +- DAQ: Mask ``PASSKEY`` variable coming from HTTP, emitted by Ecowitt .. _kotori-0.27.0: diff --git a/kotori/io/protocol/http.py b/kotori/io/protocol/http.py index 62ff15c1..b1f1eb8d 100644 --- a/kotori/io/protocol/http.py +++ b/kotori/io/protocol/http.py @@ -328,7 +328,15 @@ def read_request(self, bucket): # Data acquisition uses HTTP POST if request.method == 'POST': - return self.data_acquisition(bucket) + data = self.data_acquisition(bucket) + + # Mask `PASSKEY` ingress variable. + # https://github.com/daq-tools/kotori/discussions/122 + # https://community.hiveeyes.org/t/ecowitt-wunderground-api-fur-weather-hiveeyes-org-nutzbar/4735 + if "PASSKEY" in data: + del data["PASSKEY"] + + return data def data_acquisition(self, bucket): diff --git a/test/test_ecowitt.py b/test/test_ecowitt.py new file mode 100644 index 00000000..01bf99de --- /dev/null +++ b/test/test_ecowitt.py @@ -0,0 +1,88 @@ +import json +from test.settings.mqttkit import PROCESS_DELAY_HTTP, influx_sensors, settings +from test.util import http_form_sensor, sleep + +import pytest +import pytest_twisted +from twisted.internet import threads + + +@pytest_twisted.inlineCallbacks +@pytest.mark.http +def test_ecowitt_post(machinery, create_influxdb, reset_influxdb): + """ + Submit single reading in ``x-www-form-urlencoded`` format to HTTP API + and proof it is stored in the InfluxDB database. + """ + + # Submit a single measurement, without timestamp. + data = { + "PASSKEY": "B950C...[obliterated]", + "stationtype": "EasyWeatherPro_V5.0.6", + "runtime": "456128", + "dateutc": "2023-02-20 16:02:19", + "tempinf": "69.8", + "humidityin": "47", + "baromrelin": "29.713", + "baromabsin": "29.713", + "tempf": "48.4", + "humidity": "80", + "winddir": "108", + "windspeedmph": "1.12", + "windgustmph": "4.92", + "maxdailygust": "12.97", + "solarradiation": "1.89", + "uv": "0", + "rainratein": "0.000", + "eventrainin": "0.000", + "hourlyrainin": "0.000", + "dailyrainin": "0.028", + "weeklyrainin": "0.098", + "monthlyrainin": "0.909", + "yearlyrainin": "0.909", + "temp1f": "45.0", + "humidity1": "90", + "soilmoisture1": "46", + "soilmoisture2": "53", + "tf_ch1": "41.9", + "rrain_piezo": "0.000", + "erain_piezo": "0.000", + "hrain_piezo": "0.000", + "drain_piezo": "0.028", + "wrain_piezo": "0.043", + "mrain_piezo": "0.492", + "yrain_piezo": "0.492", + "wh65batt": "0", + "wh25batt": "0", + "batt1": "0", + "soilbatt1": "1.6", + "soilbatt2": "1.6", + "tf_batt1": "1.60", + "wh90batt": "3.04", + "freq": "868M", + "model": "HP1000SE-PRO_Pro_V1.8.5", + } + deferred = threads.deferToThread(http_form_sensor, settings.channel_path_data, data) + yield deferred + + # Check response. + response = deferred.result + assert response.status_code == 200 + assert response.content == json.dumps( + [{"type": "info", "message": "Received #1 readings"}], indent=4 + ).encode("utf-8") + + # Wait for some time to process the message. + yield sleep(PROCESS_DELAY_HTTP) + + # Proof that data arrived in InfluxDB. + record = influx_sensors.get_first_record() + + assert record["tempf"] == 48.4 + assert record["humidity"] == 80.0 + assert record["model"] == "HP1000SE-PRO_Pro_V1.8.5" + + # Make sure this will not be public. + assert "PASSKEY" not in record + + yield record