diff --git a/.gitignore b/.gitignore
index e470b09..b3c8448 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,25 @@
+# Ignore pycache
__pycache__
-.DS_Store
-.vscode/
-.coverage
-.noseids
-.pytest_cache
-nosetests.xml
-tests/report
-tests/tmp.db
-logs/
\ No newline at end of file
+
+# Ignore .hidden files
+.*
+
+# Except .
+!.github/
+!.gitignore
+
+# Ignore items in test (report, cache, etc), except files starting with test
+tests/*
+!tests/test*
+!tests/test_certs
+!tests/pytest.ini
+
+# Ignore logs/data/certs
+logs/*
+data/*
+certs/*
+
+# Except README in logs/data/certs
+!logs/README.md
+!data/README.md
+!certs/README.md
diff --git a/.travis.yml b/.travis.yml
index 3b82981..1b952c6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ install:
- pip install pipenv
- pipenv install --dev
-script: pipenv run python -m pytest --cov=./
+script: pipenv run python -m pytest --cov=./ tests
after_success:
- codecov
\ No newline at end of file
diff --git a/Pipfile b/Pipfile
index 6f8a142..bfb75b6 100644
--- a/Pipfile
+++ b/Pipfile
@@ -20,6 +20,8 @@ pytest-aiohttp = "*"
pytest-cov = "*"
testfixtures = "*"
codecov = "*"
+autoflake = "*"
+pytest-env = "*"
[pipenv]
allow_prereleases = true
diff --git a/Pipfile.lock b/Pipfile.lock
index 6e256b6..05354a2 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "243154e4a18d9995bb246342d1ed65910cda2fa674bced665a9706fc385459fc"
+ "sha256": "309c2ca578f67a8663325695e4d283f7e3f604c7cec451bf57e71af7dcdb7294"
},
"pipfile-spec": 6,
"requires": {},
@@ -127,20 +127,20 @@
},
"pyyaml": {
"hashes": [
- "sha256:1adecc22f88d38052fb787d959f003811ca858b799590a5eaa70e63dca50308c",
- "sha256:436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95",
- "sha256:460a5a4248763f6f37ea225d19d5c205677d8d525f6a83357ca622ed541830c2",
- "sha256:5a22a9c84653debfbf198d02fe592c176ea548cccce47553f35f466e15cf2fd4",
- "sha256:7a5d3f26b89d688db27822343dfa25c599627bc92093e788956372285c6298ad",
- "sha256:9372b04a02080752d9e6f990179a4ab840227c6e2ce15b95e1278456664cf2ba",
- "sha256:a5dcbebee834eaddf3fa7366316b880ff4062e4bcc9787b78c7fbb4a26ff2dd1",
- "sha256:aee5bab92a176e7cd034e57f46e9df9a9862a71f8f37cad167c6fc74c65f5b4e",
- "sha256:c51f642898c0bacd335fc119da60baae0824f2cde95b0330b56c0553439f0673",
- "sha256:c68ea4d3ba1705da1e0d85da6684ac657912679a649e8868bd850d2c299cce13",
- "sha256:e23d0cc5299223dcc37885dae624f382297717e459ea24053709675a976a3e19"
+ "sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3",
+ "sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043",
+ "sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7",
+ "sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265",
+ "sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391",
+ "sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778",
+ "sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225",
+ "sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955",
+ "sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e",
+ "sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190",
+ "sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd"
],
"index": "pypi",
- "version": "==5.1"
+ "version": "==5.1.1"
},
"six": {
"hashes": [
@@ -271,6 +271,13 @@
],
"version": "==19.1.0"
},
+ "autoflake": {
+ "hashes": [
+ "sha256:6b59e5b9b82e30077499578856282debb81186d10b4f899e8c2e1d616cdef973"
+ ],
+ "index": "pypi",
+ "version": "==1.3"
+ },
"black": {
"hashes": [
"sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf",
@@ -471,6 +478,13 @@
],
"version": "==1.8.0"
},
+ "pyflakes": {
+ "hashes": [
+ "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
+ "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
+ ],
+ "version": "==2.1.1"
+ },
"pylint": {
"hashes": [
"sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09",
@@ -517,6 +531,13 @@
"index": "pypi",
"version": "==2.7.1"
},
+ "pytest-env": {
+ "hashes": [
+ "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2"
+ ],
+ "index": "pypi",
+ "version": "==0.6.2"
+ },
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
diff --git a/README.md b/README.md
index 8e338c0..83ce61e 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,10 @@ Bumper is a standalone and self-hosted implementation of the central server used
**Note:** The current master branch is unstable, and in active development.
-| Master Build Status | Status |
-|--|--|
-|AppVeyor (Win32) | |
-|TravisCI (Linux) | |
+| Master Build Status | Status |
+| ------------------- | ---------------------------------------------------------------------- |
+| AppVeyor (Win32) |  |
+| TravisCI (Linux) |  |
Code Test Coverage: 
@@ -20,13 +20,13 @@ Bumper needs users to assist with testing in order to ensure compatability as bu
As work to reverse the protocols and provide a self-hosted central server is still in progress, Bumper has had limited testing. There are a number of EcoVacs models that it hasn't been tested against. Bumper should be compatible with most wifi-enabled robots that use either the Ecovacs Android/iOS app or the Ecovacs Home Android/iOS app, but has only been reported to work on the below:
-| Model | Protocol Used | Bumper Version Tested | EcoVacs App Tested |
-|--|--|--|--|
-| Deebot 900/901 | MQTT | master | Ecovacs/Ecovacs Home |
-| Deebot 600 | MQTT | master | Ecovacs Home |
-| Deebot Ozmo 601 | XMPP | master | Ecovacs |
-| Deebot Ozmo 930 | XMPP | master | Ecovacs |
-| Deebot M81 Pro | XMPP | v0.1.0 | Ecovacs |
+| Model | Protocol Used | Bumper Version Tested | EcoVacs App Tested |
+| --------------- | ------------- | --------------------- | -------------------- |
+| Deebot 900/901 | MQTT | master | Ecovacs/Ecovacs Home |
+| Deebot 600 | MQTT | master | Ecovacs Home |
+| Deebot Ozmo 601 | XMPP | master | Ecovacs |
+| Deebot Ozmo 930 | XMPP | master | Ecovacs |
+| Deebot M81 Pro | XMPP | v0.1.0 | Ecovacs |
For more information about the protocols and how Bumper works, see the [How does it work?](docs/How_It_Works.md) page in the docs. If you test against another model and it works, please open an issue to report it.
@@ -64,14 +64,36 @@ But seriously, there are a several reasons for eliminating the central server:
### Starting Bumper
-- Start Bumper with `pipenv run python start_bumper.py`
+Bumper requires certificates to function. If certificates aren't found it will prompt to generate them for you.
+
+For more information on generating certificates manually, see the [Creating Certs](docs/Create_Certs.md) doc
+
+- Start Bumper with `pipenv run python -m bumper`
+ - If prompted to generate certificates choose yes or no
- Reboot your robot
- **Note:** Some models may require removing and re-inserting the battery pack.
- This doesn't seem to be required for models that don't have easily accessible batteries such as the 900/901.
-
- If your configuration is correct, the robot will connect to Bumper within about 30 seconds. Bumper will output information about the connection status.
+#### Command-Line Usage
+
+`start_bumper.py` is a helper script that starts up Bumper for you. It has a number of available command-line arguments that can be viewed by adding the `-h` flag.
+
+ ````
+ usage: start_bumper.py [-h] [--listen LISTEN] [--announce ANNOUNCE] [--debug]
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --listen LISTEN start serving on address
+ --announce ANNOUNCE announce address to bots on checkin
+ --debug enable debug logs
+ ````
+
+#### Environment Variables
+
+Bumper looks for a number of Environment Variables at initialization allowing for customizing a number of settings. For more information see the [Environment Variables](docs/Env_Var.md) doc.
+
## Thanks
A big thanks to the original project creator @torbjornaxelsson, without his work this project would have taken much longer to build.
diff --git a/appveyor.yml b/appveyor.yml
index cd58fa4..56cc65c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -19,7 +19,7 @@ test_script:
# Note that you must use the environment variable %PYTHON% to refer to
# the interpreter you're using - Appveyor does not do anything special
# to put the Python version you want to use on PATH.
- - "pipenv run python -m pytest --cov=./"
+ - "pipenv run python -m pytest --cov=./ tests"
after_test:
- "pipenv run python -m codecov"
\ No newline at end of file
diff --git a/bumper/__init__.py b/bumper/__init__.py
index 4280b1b..104a120 100644
--- a/bumper/__init__.py
+++ b/bumper/__init__.py
@@ -5,27 +5,65 @@ from bumper.mqttserver import MQTTServer, MQTTHelperBot
from bumper.xmppserver import XMPPServer
import asyncio
import json
-import time
from datetime import datetime, timedelta
-import platform
-import os, sys
+import os
import logging
from logging.handlers import RotatingFileHandler
-from base64 import b64decode, b64encode
from tinydb import TinyDB, Query
-import json
from tinydb.storages import MemoryStorage
+import socket
+import sys
-ca_cert = "./certs/CA/cacert.pem"
-server_cert = "./certs/cert.pem"
-server_key = "./certs/key.pem"
+
+def strtobool(strbool):
+ if str(strbool).lower() in ["true", "1", "t", "y", "on", "yes"]:
+ return True
+ else:
+ return False
+
+
+# os.environ['PYTHONASYNCIODEBUG'] = '1' # Uncomment to enable ASYNCIODEBUG
+
+bumper_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+# Set defaults from environment variables first
+# Certs
+ca_cert = os.environ.get("BUMPER_CA") or os.path.join(bumper_dir, "certs", "ca.crt")
+server_cert = os.environ.get("BUMPER_CERT") or os.path.join(
+ bumper_dir, "certs", "bumper.crt"
+)
+server_key = os.environ.get("BUMPER_KEY") or os.path.join(
+ bumper_dir, "certs", "bumper.key"
+)
+
+# Folders
+logs_dir = os.environ.get("BUMPER_LOGS") or os.path.join(bumper_dir, "logs")
+os.makedirs(logs_dir, exist_ok=True) # Ensure logs directory exists or create
+data_dir = os.environ.get("BUMPER_DATA") or os.path.join(bumper_dir, "data")
+os.makedirs(data_dir, exist_ok=True) # Ensure data directory exists or create
+
+# Listeners
+bumper_listen = os.environ.get("BUMPER_LISTEN") or socket.gethostbyname(
+ socket.gethostname()
+)
+
+
+bumper_announce_ip = os.environ.get("BUMPER_ANNOUNCE_IP") or bumper_listen
+
+# Other
+bumper_debug = strtobool(os.environ.get("BUMPER_DEBUG")) or False
use_auth = False
token_validity_seconds = 3600 # 1 hour
db = None
-# Logs
-os.makedirs("logs", exist_ok=True) # Ensure logs directory exists or create
+mqtt_server = None
+mqtt_helperbot = None
+conf_server = None
+conf_server_2 = None
+xmpp_server = None
+
+shutting_down = False
+
# Set format for all logs
logformat = logging.Formatter(
"[%(asctime)s] :: %(levelname)s :: %(name)s :: %(module)s :: %(funcName)s :: %(lineno)d :: %(message)s"
@@ -74,9 +112,121 @@ xmppserverlog.addHandler(xmpp_rotate)
# Override the logging level
# xmppserverlog.setLevel(logging.INFO)
-
logging.getLogger("asyncio").setLevel(logging.CRITICAL + 1) # Ignore this logger
+mqtt_listen_address = bumper_listen
+mqtt_listen_port = 8883
+conf1_listen_address = bumper_listen
+conf1_listen_port = 443
+conf2_listen_address = bumper_listen
+conf2_listen_port = 8007
+xmpp_listen_address = bumper_listen
+xmpp_listen_port = 5223
+
+async def start():
+
+ try:
+ loop = asyncio.get_event_loop()
+ except:
+ loop = asyncio.new_event_loop()
+
+ if bumper_debug:
+ logging.basicConfig(
+ level=logging.DEBUG,
+ format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(module)s :: %(funcName)s :: %(lineno)d :: %(message)s",
+ )
+ loop.set_debug(True) # Set asyncio loop to debug
+ # logging.getLogger("asyncio").setLevel(logging.DEBUG) # Show debug asyncio logs (disabled in init, uncomment for debugging asyncio)
+ else:
+ logging.basicConfig(
+ level=logging.INFO,
+ format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s",
+ )
+
+ if not bumper_listen:
+ logging.log(logging.FATAL, "No listen address configured")
+ return
+
+ if not (
+ os.path.exists(ca_cert)
+ and os.path.exists(server_cert)
+ and os.path.exists(server_key)
+ ):
+ logging.log(logging.FATAL, "Certificate(s) don't exist at paths specified")
+ return
+
+ bumperlog.info("Starting Bumper")
+ global mqtt_server
+ mqtt_server = MQTTServer((mqtt_listen_address, mqtt_listen_port))
+ global mqtt_helperbot
+ mqtt_helperbot = MQTTHelperBot((mqtt_listen_address, mqtt_listen_port))
+ global conf_server
+ conf_server = ConfServer(
+ (conf1_listen_address, conf1_listen_port), usessl=True, helperbot=mqtt_helperbot
+ )
+ global conf_server_2
+ conf_server_2 = ConfServer(
+ (conf2_listen_address, conf2_listen_port), usessl=False, helperbot=mqtt_helperbot
+ )
+ global xmpp_server
+ xmpp_server = XMPPServer((xmpp_listen_address, xmpp_listen_port))
+
+ # Start web servers
+ conf_server.confserver_app()
+ asyncio.create_task(conf_server.start_server())
+
+ conf_server_2.confserver_app()
+ asyncio.create_task(conf_server_2.start_server())
+
+ # Start MQTT Server
+ asyncio.create_task(mqtt_server.broker_coro())
+
+ # Start MQTT Helperbot
+ asyncio.create_task(mqtt_helperbot.start_helper_bot())
+
+ # Start XMPP Server
+ asyncio.create_task(xmpp_server.start_async_server())
+
+ # Start maintenance
+ while not shutting_down:
+ asyncio.create_task(maintenance())
+ await asyncio.sleep(5)
+
+
+async def maintenance():
+ revoke_expired_tokens()
+
+
+async def shutdown():
+ try:
+ bumperlog.info("Shutting down")
+
+ await conf_server.stop_server()
+ await conf_server_2.stop_server()
+ if mqtt_server.broker.transitions.state == "started":
+ await mqtt_server.broker.shutdown()
+ elif mqtt_server.broker.transitions.state == "starting":
+ while mqtt_server.broker.transitions.state == "starting":
+ await asyncio.sleep(0.1)
+ if mqtt_server.broker.transitions.state == "started":
+ await mqtt_server.broker.shutdown()
+ await mqtt_helperbot.Client.disconnect()
+ if xmpp_server.server:
+ if xmpp_server.server._serving:
+ xmpp_server.server.close()
+ await xmpp_server.server.wait_closed()
+ global shutting_down
+ shutting_down = True
+
+ except asyncio.CancelledError:
+ bumperlog.info("Coroutine canceled")
+
+ except Exception as e:
+ bumperlog.info("Exception: {}".format(e))
+
+ finally:
+ bumperlog.info("Shutdown complete")
+
def get_milli_time(timetoconvert):
return int(round(timetoconvert * 1000))
@@ -89,20 +239,8 @@ def db_file():
return os_db_path()
-def os_db_path(createdir=True):
- # createdir - Set to False during tests to not create paths
- if platform.system() == "Windows":
- if createdir:
- os.makedirs(
- os.getenv("APPDATA"), exist_ok=True
- ) # Ensure db_path directory exists or create
- return os.path.join(os.getenv("APPDATA"), "bumper.db")
- else:
- if createdir:
- os.makedirs(
- os.path.expanduser("~/.config"), exist_ok=True
- ) # Ensure db_path directory exists or create
- return os.path.expanduser("~/.config/bumper.db")
+def os_db_path(): # createdir=True):
+ return os.path.join(data_dir, "bumper.db")
def db_get():
@@ -300,12 +438,6 @@ class VacBotDevice(object):
"xmpp_connection": self.xmpp_connection,
}
- def toJSON(self):
- return json.dumps(
- self, default=lambda o: o.__dict__, sort_keys=False
- ) # , indent=4)
-
-
class GlobalVacBotDevice(VacBotDevice): # EcoVacs Home
UILogicId = ""
ota = True
@@ -811,3 +943,111 @@ API_ERRORS = {
ERR_WRONG_EMAIL_ADDRESS: "1008",
ERR_WRONG_PWD_FROMATE: "1009",
}
+
+def create_certs():
+ import platform
+ import os
+ import subprocess
+ import sys
+ path = os.path.dirname(sys.modules[__name__].__file__)
+ path = os.path.join(path, "..")
+ sys.path.insert(0, path)
+
+ print("Creating certificates")
+ odir = os.path.realpath(os.curdir)
+ os.chdir("certs")
+ if str(platform.system()).lower() == "windows":
+ # run for win
+ subprocess.run(
+ [os.path.join("..", "create_certs", "create_certs_windows.exe")]
+ )
+ elif str(platform.system()).lower() == "darwin":
+ # run on mac
+ subprocess.run([os.path.join("..", "create_certs", "create_certs_osx")])
+ elif str(platform.system()).lower() == "linux":
+ if "arm" in platform.machine().lower():
+ # run for pi
+ subprocess.run([os.path.join("..", "create_certs", "create_certs_rpi")])
+ else:
+ # run for linux
+ subprocess.run(
+ [os.path.join("..", "create_certs", "create_certs_linux")]
+ )
+
+ else:
+ logging.log(logging.FATAL, "Can't determine platform. Create certs manually and try again.")
+ return
+
+ print("Certificates created")
+ os.chdir(odir)
+ print(os.path.realpath(os.curdir))
+ if "__main__.py" in sys.argv[0]:
+ os.execv(
+ sys.executable, ["python", "-m", "bumper"] + sys.argv[1:]
+ ) # Start again
+
+ else:
+ os.execv(sys.executable, ["python"] + sys.argv) # Start again
+
+def firstrun_input():
+ return input(
+ "No certificates found, would you like to create them automatically? (y/n): "
+ ).lower()
+
+def first_run():
+ yes = {"yes", "y", "ye", ""}
+ print("")
+ if firstrun_input() in yes:
+ create_certs()
+
+ else:
+ logging.log(logging.FATAL, "Can't continue without certificates, please create some then try again.")
+
+def main(argv=None):
+ import argparse
+ global bumper_debug
+ global bumper_listen
+ global bumper_announce_ip
+
+ try:
+
+ if not (
+ os.path.exists(ca_cert)
+ and os.path.exists(server_cert)
+ and os.path.exists(server_key)
+ ):
+ first_run()
+ return
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--listen", type=str, default=None, help="start serving on address"
+ )
+ parser.add_argument(
+ "--announce", type=str, default=None, help="announce address to bots on checkin"
+ )
+ parser.add_argument("--debug", action="store_true", help="enable debug logs")
+ args = parser.parse_args(args=argv)
+
+ if args.debug:
+ bumper_debug = True
+
+ if args.listen:
+ bumper_listen = args.listen
+
+ if args.announce:
+ bumper_announce_ip = args.announce
+
+ asyncio.run(start())
+
+ except KeyboardInterrupt:
+ bumperlog.info("Keyboard Interrupt!")
+ pass
+
+ except Exception as e:
+ bumperlog.exception(e)
+ pass
+
+ finally:
+ asyncio.run(shutdown())
+
diff --git a/bumper/__main__.py b/bumper/__main__.py
new file mode 100644
index 0000000..7434132
--- /dev/null
+++ b/bumper/__main__.py
@@ -0,0 +1,4 @@
+import bumper
+
+if __name__ == "__main__":
+ bumper.main()
\ No newline at end of file
diff --git a/bumper/confserver.py b/bumper/confserver.py
index 5180769..afc9fe1 100644
--- a/bumper/confserver.py
+++ b/bumper/confserver.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-from threading import Thread
-import socket, logging, ssl, json
+import json
+import logging
+import ssl
import string
import random
import bumper
-import time
from datetime import datetime, timedelta
import asyncio
from aiohttp import web
@@ -63,6 +63,8 @@ class ConfServer:
self.confthread = None
self.run_async = False
self.app = None
+ self.site = None
+ self.runner = None
def confserver_app(self):
self.app = web.Application(loop=asyncio.get_event_loop())
@@ -167,36 +169,43 @@ class ConfServer:
confserverlog.info(
"Starting ConfServer at {}:{}".format(self.address[0], self.address[1])
)
- runner = web.AppRunner(self.app)
- await runner.setup()
+ self.runner = web.AppRunner(self.app)
+ await self.runner.setup()
if self.usessl:
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain(bumper.server_cert, bumper.server_key)
- site = web.TCPSite(
- runner,
+ self.site = web.TCPSite(
+ self.runner,
host=self.address[0],
port=self.address[1],
ssl_context=ssl_ctx,
)
else:
- site = web.TCPSite(runner, host=self.address[0], port=self.address[1])
+ self.site = web.TCPSite(
+ self.runner, host=self.address[0], port=self.address[1]
+ )
- await site.start()
+ await self.site.start()
except PermissionError as e:
- if "bind" in e.strerror:
- confserverlog.exception(
- "Error binding confserver, exiting. Try using a different hostname or IP - {}".format(
- e
- )
- )
- exit(1)
+ confserverlog.error(e.strerror)
+ asyncio.create_task(bumper.shutdown())
+
+ except asyncio.CancelledError:
+ pass
+
+ except Exception as e:
+ confserverlog.exception("{}".format(e))
+ asyncio.create_task(bumper.shutdown())
+
+ async def stop_server(self):
+ try:
+ await self.runner.shutdown()
except Exception as e:
confserverlog.exception("{}".format(e))
- exit(1)
async def handle_base(self, request):
try:
@@ -877,19 +886,26 @@ class ConfServer:
if todo == "FindBest":
service = postbody["service"]
if service == "EcoMsgNew":
- srvip = socket.gethostbyname(socket.gethostname())
+ srvip = bumper.bumper_announce_ip
srvport = 5223
confserverlog.info(
- "Reporting FindBest-EcoMsgNew Server to Bot as: {}:{}".format(
+ "Announcing EcoMsgNew Server to bot as: {}:{}".format(
srvip, srvport
)
)
- body = {"result": "ok", "ip": srvip, "port": srvport}
+ msgserver = {"ip": srvip, "port": srvport, "result": "ok"}
+ msgserver = json.dumps(msgserver)
+ msgserver = msgserver.replace(
+ " ", ""
+ ) # bot seems to be very picky about having no spaces, only way was with text
+
+ return web.json_response(text=msgserver)
+
elif service == "EcoUpdate":
srvip = "47.88.66.164" # EcoVacs Server
srvport = 8005
confserverlog.info(
- "Reporting FindBest-EcoUpdate Server to Bot as: {}:{}".format(
+ "Announcing EcoUpdate Server to bot as: {}:{}".format(
srvip, srvport
)
)
@@ -937,9 +953,7 @@ class ConfServer:
bumper.bot_remove(postbody["did"])
body = {"result": "ok", "todo": "result"}
- confserverlog.debug(
- "\r\n POST: {} \r\n Response: {}".format(postbody, body)
- )
+ confserverlog.debug("POST: {} - Response: {}".format(postbody, body))
return web.json_response(body)
@@ -982,9 +996,7 @@ class ConfServer:
"todo": "result",
}
- confserverlog.debug(
- "\r\n POST: {} \r\n Response: {}".format(postbody, body)
- )
+ confserverlog.debug("POST: {} - Response: {}".format(postbody, body))
return web.json_response(body)
@@ -1012,10 +1024,10 @@ class ConfServer:
if todo == "FindBest":
service = postbody["service"]
if service == "EcoMsgNew":
- srvip = socket.gethostbyname(socket.gethostname())
+ srvip = bumper.bumper_announce_ip
srvport = 5223
confserverlog.info(
- "Reporting FindBest-EcoMsgNew Server to Bot as: {}:{}".format(
+ "Announcing EcoMsgNew Server to bot as: {}:{}".format(
srvip, srvport
)
)
@@ -1025,17 +1037,18 @@ class ConfServer:
" ", ""
) # bot seems to be very picky about having no spaces, only way was with text
- confserverlog.debug(
- "\r\n POST: {} \r\n Response: {}".format(postbody, msgserver)
- )
return web.json_response(text=msgserver)
elif service == "EcoUpdate":
- body = {"result": "ok", "ip": "47.88.66.164", "port": 8005}
+ srvip = "47.88.66.164" # EcoVacs Server
+ srvport = 8005
+ confserverlog.info(
+ "Announcing EcoUpdate Server to bot as: {}:{}".format(
+ srvip, srvport
+ )
+ )
+ body = {"result": "ok", "ip": srvip, "port": srvport}
- confserverlog.debug(
- "\r\n POST: {} \r\n Response: {}".format(postbody, body)
- )
return web.json_response(body)
except Exception as e:
@@ -1097,7 +1110,7 @@ class ConfServer:
body = {"ret": "ok", "logs": []}
confserverlog.debug(
- "\r\n POST: {} \r\n Response: {}".format(json_body, body)
+ "POST: {} - Response: {}".format(json_body, body)
)
return web.json_response(body)
diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py
index 4edaca7..5e247a4 100644
--- a/bumper/mqttserver.py
+++ b/bumper/mqttserver.py
@@ -9,8 +9,6 @@ from hbmqtt.client import MQTTClient
from hbmqtt.mqtt.constants import QOS_0, QOS_1, QOS_2
import pkg_resources
import time
-from threading import Thread
-import ssl
import bumper
import json
from datetime import datetime, timedelta
@@ -60,8 +58,20 @@ class MQTTHelperBot:
("iot/atr/+", QOS_0),
]
)
+
asyncio.create_task(self.get_msg())
+ except ConnectionRefusedError as e:
+ helperbotlog.Error(e)
+ pass
+
+ except asyncio.CancelledError as e:
+ pass
+
+ except hbmqtt.client.ConnectException as e:
+ helperbotlog.Error(e)
+ pass
+
except Exception as e:
helperbotlog.exception("{}".format(e))
@@ -194,25 +204,23 @@ class MQTTServer:
broker = None
async def broker_coro(self):
+
+ mqttserverlog.info(
+ "Starting MQTT Server at {}:{}".format(self.address[0], self.address[1])
+ )
+ self.broker = hbmqtt.broker.Broker(config=self.default_config)
+
try:
- mqttserverlog.info(
- "Starting MQTT Server at {}:{}".format(self.address[0], self.address[1])
- )
- self.broker = hbmqtt.broker.Broker(config=self.default_config)
await self.broker.start()
- except PermissionError as e:
- if "bind" in e.strerror:
- mqttserverlog.exception(
- "Error binding mqttserver, exiting. Try using a different hostname or IP - {}".format(
- e
- )
- )
- exit(1)
+ except hbmqtt.broker.BrokerException as e:
+ mqttserverlog.exception(e)
+ asyncio.create_task(bumper.shutdown())
+ pass
except Exception as e:
mqttserverlog.exception("{}".format(e))
- exit(1)
+ asyncio.create_task(bumper.shutdown())
def __init__(self, address):
try:
@@ -300,10 +308,8 @@ class BumperMQTTServer_Plugin:
"eco-ng",
)
- mqttserverlog.debug(
- "new bot authenticated SN: {} DID: {}".format(
- username, didsplit[0]
- )
+ mqttserverlog.info(
+ "bot authenticated SN: {} DID: {}".format(username, didsplit[0])
)
authenticated = True
@@ -324,9 +330,7 @@ class BumperMQTTServer_Plugin:
if auth:
bumper.client_add(userid, realm, resource)
- mqttserverlog.debug(
- "client authenticated {}".format(userid)
- )
+ mqttserverlog.info("client authenticated {}".format(userid))
authenticated = True
else:
diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py
index 453de22..ef43a58 100644
--- a/bumper/xmppserver.py
+++ b/bumper/xmppserver.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
-from threading import Thread
-import sys, socket, threading, re, time, logging, uuid, xml.etree.ElementTree as ET
+import logging
+import re
+import uuid
+import xml.etree.ElementTree as ET
import base64
import ssl
import bumper
-import asyncio, functools
+import asyncio
xmppserverlog = logging.getLogger("xmppserver")
@@ -22,17 +24,30 @@ class XMPPServer:
self.xmpp_protocol = lambda: XMPPServer_Protocol()
async def start_async_server(self):
- xmppserverlog.info(
- "Starting XMPP Server at {}:{}".format(self.address[0], self.address[1])
- )
+ try:
+ xmppserverlog.info(
+ "Starting XMPP Server at {}:{}".format(self.address[0], self.address[1])
+ )
- loop = asyncio.get_running_loop()
+ loop = asyncio.get_running_loop()
- self.server = await loop.create_server(
- self.xmpp_protocol, host=self.address[0], port=self.address[1]
- )
+ self.server = await loop.create_server(
+ self.xmpp_protocol, host=self.address[0], port=self.address[1]
+ )
- self.server_coro = loop.create_task(self.server.serve_forever())
+ self.server_coro = loop.create_task(self.server.serve_forever())
+
+ except PermissionError as e:
+ xmppserverlog.error(e.strerror)
+ asyncio.create_task(bumper.shutdown())
+ pass
+
+ except asyncio.CancelledError:
+ pass
+
+ except Exception as e:
+ xmppserverlog.exception("{}".format(e))
+ asyncio.create_task(bumper.shutdown())
def disconnect(self):
try:
@@ -51,10 +66,6 @@ class XMPPServer:
class XMPPServer_Protocol(asyncio.Protocol):
client_id = None
exit_flag = False
- server_cert = "./certs/cert.pem"
- server_key = "./certs/key.pem"
- ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
- ssl_ctx.load_cert_chain(server_cert, server_key)
aclient = None
def connection_made(self, transport):
@@ -506,7 +517,7 @@ class XMPPAsyncClient:
if self.devclass: # if there is a devclass it is a bot
bumper.bot_add(self.uid, self.uid, self.devclass, "atom", "eco-legacy")
self.type = self.BOT
- xmppserverlog.debug("bot authenticated {}".format(self.uid))
+ xmppserverlog.info("bot authenticated SN: {}".format(self.uid))
# Send response
self.send(
''
@@ -525,7 +536,7 @@ class XMPPAsyncClient:
if auth:
self.type = self.CONTROLLER
bumper.client_add(self.uid, "bumper", self.clientresource)
- xmppserverlog.debug("client authenticated {}".format(self.uid))
+ xmppserverlog.info("client authenticated {}".format(self.uid))
# Client authenticated, move to next state
self._set_state("INIT")
diff --git a/certs/CA/cacert.crt b/certs/CA/cacert.crt
deleted file mode 100644
index 6d6a03e..0000000
Binary files a/certs/CA/cacert.crt and /dev/null differ
diff --git a/certs/CA/cacert.pem b/certs/CA/cacert.pem
deleted file mode 100644
index a219c22..0000000
--- a/certs/CA/cacert.pem
+++ /dev/null
@@ -1,85 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 11078087720677522868 (0x99bd46167599bdb4)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Validity
- Not Before: Feb 1 05:59:32 2019 GMT
- Not After : Jan 29 05:59:32 2029 GMT
- Subject: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:aa:6e:af:15:99:3b:09:32:a1:a7:4b:ee:f7:13:
- 68:c1:94:4f:09:71:54:99:02:2d:27:c1:5f:16:2e:
- 45:d3:a6:44:24:fb:bd:f0:9b:a9:f6:6c:49:6f:09:
- 13:76:d6:5b:88:c2:fc:8b:8b:14:4c:39:df:8a:b5:
- 51:a8:83:c1:73:ca:aa:f1:b7:b4:38:e1:f0:91:35:
- be:6f:c6:99:7c:e1:ef:d9:c0:ee:d5:fb:f8:f5:0f:
- a7:96:b3:78:95:d6:2a:04:7d:3b:31:42:b6:33:c0:
- 36:2c:06:f1:6d:db:11:99:16:3e:77:c6:c6:df:ed:
- 95:40:b8:39:a2:82:40:fe:bb:f6:8b:63:0c:c6:96:
- ae:fd:3b:c7:79:a4:f5:5f:4e:83:87:27:33:bb:6f:
- cf:43:86:55:73:6c:0c:28:61:89:66:72:b3:90:3d:
- d8:54:53:6a:3a:57:76:01:05:58:ac:78:3d:0d:0a:
- 52:b4:b7:be:2b:4e:9a:6a:f4:f8:a2:3f:21:99:b6:
- b4:74:fb:d5:c0:23:7b:e8:51:f5:0a:ec:6a:11:4e:
- 9b:c3:f2:56:00:06:3b:58:e3:cf:67:b6:c3:26:50:
- 0e:f7:72:11:3f:39:2c:c9:b7:d5:69:1a:33:dc:8f:
- 81:66:c5:88:3f:c7:01:94:f0:3d:ac:aa:f3:a0:2a:
- e8:c7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
- X509v3 Authority Key Identifier:
- keyid:5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
- DirName:/C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
- serial:99:BD:46:16:75:99:BD:B4
-
- X509v3 Basic Constraints:
- CA:TRUE
- X509v3 Subject Alternative Name:
- email:null@null.com
- Signature Algorithm: sha1WithRSAEncryption
- 5e:45:c7:34:7f:9b:a4:6b:cc:3c:e7:34:84:76:ee:ec:98:be:
- 0f:de:ab:b2:a5:6d:59:18:eb:20:de:a4:fc:2c:4d:e4:9a:9c:
- 63:99:be:16:6a:1d:c0:57:73:e8:7f:9e:78:4d:2a:e6:11:a3:
- b6:57:18:84:6e:ae:a7:97:08:7e:1f:4d:33:fc:46:06:a7:d1:
- 6e:3a:d1:d9:ef:ba:fd:87:b8:e0:ea:51:85:d2:a6:de:49:e1:
- a6:43:d1:26:15:e2:f9:8b:8c:f0:94:fe:a3:62:dd:cc:ab:be:
- a5:dc:90:d8:28:0c:85:4b:fb:df:4a:f1:ac:35:86:7f:63:fd:
- ca:c6:aa:29:0b:b0:e1:e3:08:e6:4c:71:d2:08:32:c9:09:22:
- 6c:61:ec:87:49:8d:77:48:7a:f7:75:86:bb:4e:17:b0:fe:43:
- 4d:2f:95:bd:d5:0f:c1:ef:ba:f7:3e:e0:b6:2f:fa:4a:c9:45:
- 36:97:56:a4:6d:af:86:88:ff:98:2f:b2:e4:04:4d:c4:02:20:
- fc:66:8c:d5:2b:e9:5a:6c:1f:d2:67:34:c3:39:7e:f4:c7:37:
- 53:6b:11:99:a8:29:8b:3f:f6:3a:82:ae:f5:2c:d5:b7:23:88:
- bb:03:84:ad:cb:d0:f6:8d:24:9f:54:08:d1:39:da:1a:a9:f6:
- 1b:c9:53:65
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIJAJm9RhZ1mb20MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQKEwZCdW1wZXIxDzAN
-BgNVBAsTBkJ1bXBlcjEPMA0GA1UEAxMGQnVtcGVyMB4XDTE5MDIwMTA1NTkzMloX
-DTI5MDEyOTA1NTkzMlowVTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
-aWExDzANBgNVBAoTBkJ1bXBlcjEPMA0GA1UECxMGQnVtcGVyMQ8wDQYDVQQDEwZC
-dW1wZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqbq8VmTsJMqGn
-S+73E2jBlE8JcVSZAi0nwV8WLkXTpkQk+73wm6n2bElvCRN21luIwvyLixRMOd+K
-tVGog8Fzyqrxt7Q44fCRNb5vxpl84e/ZwO7V+/j1D6eWs3iV1ioEfTsxQrYzwDYs
-BvFt2xGZFj53xsbf7ZVAuDmigkD+u/aLYwzGlq79O8d5pPVfToOHJzO7b89DhlVz
-bAwoYYlmcrOQPdhUU2o6V3YBBViseD0NClK0t74rTppq9PiiPyGZtrR0+9XAI3vo
-UfUK7GoRTpvD8lYABjtY489ntsMmUA73chE/OSzJt9VpGjPcj4FmxYg/xwGU8D2s
-qvOgKujHAgMBAAGjgdIwgc8wHQYDVR0OBBYEFF45x3gxgzBRgtmIm3MLcu9EdHvV
-MIGFBgNVHSMEfjB8gBReOcd4MYMwUYLZiJtzC3LvRHR71aFZpFcwVTELMAkGA1UE
-BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAoTBkJ1bXBlcjEPMA0G
-A1UECxMGQnVtcGVyMQ8wDQYDVQQDEwZCdW1wZXKCCQCZvUYWdZm9tDAMBgNVHRME
-BTADAQH/MBgGA1UdEQQRMA+BDW51bGxAbnVsbC5jb20wDQYJKoZIhvcNAQEFBQAD
-ggEBAF5FxzR/m6RrzDznNIR27uyYvg/eq7KlbVkY6yDepPwsTeSanGOZvhZqHcBX
-c+h/nnhNKuYRo7ZXGIRurqeXCH4fTTP8Rgan0W460dnvuv2HuODqUYXSpt5J4aZD
-0SYV4vmLjPCU/qNi3cyrvqXckNgoDIVL+99K8aw1hn9j/crGqikLsOHjCOZMcdII
-MskJImxh7IdJjXdIevd1hrtOF7D+Q00vlb3VD8Hvuvc+4LYv+krJRTaXVqRtr4aI
-/5gvsuQETcQCIPxmjNUr6VpsH9JnNMM5fvTHN1NrEZmoKYs/9jqCrvUs1bcjiLsD
-hK3L0PaNJJ9UCNE52hqp9hvJU2U=
------END CERTIFICATE-----
diff --git a/certs/CA/careq.pem b/certs/CA/careq.pem
deleted file mode 100644
index f4c94e5..0000000
--- a/certs/CA/careq.pem
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIIC2TCCAcECAQAwaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx
-EjAQBgNVBAcTCUhhd3Rob3JuZTEPMA0GA1UEChMGQnVtcGVyMQ8wDQYDVQQLEwZC
-dW1wZXIxDzANBgNVBAMTBkJ1bXBlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBAKpurxWZOwkyoadL7vcTaMGUTwlxVJkCLSfBXxYuRdOmRCT7vfCbqfZs
-SW8JE3bWW4jC/IuLFEw534q1UaiDwXPKqvG3tDjh8JE1vm/GmXzh79nA7tX7+PUP
-p5azeJXWKgR9OzFCtjPANiwG8W3bEZkWPnfGxt/tlUC4OaKCQP679otjDMaWrv07
-x3mk9V9Og4cnM7tvz0OGVXNsDChhiWZys5A92FRTajpXdgEFWKx4PQ0KUrS3vitO
-mmr0+KI/IZm2tHT71cAje+hR9QrsahFOm8PyVgAGO1jjz2e2wyZQDvdyET85LMm3
-1WkaM9yPgWbFiD/HAZTwPayq86Aq6McCAwEAAaArMCkGCSqGSIb3DQEJDjEcMBow
-GAYDVR0RBBEwD4ENbnVsbEBudWxsLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAQU/v
-8GRj5M3Qs0at2UGxz7uKZF5RKt6hE5WreS/joaMkK4+kTqA8FsfCGz0zUyyLWNKh
-1o4b99yvYXG+rP8euMyBql/WSnEcF0KYrrGyUjH0qQQfTHqC0UqolvqoQCkPbvUO
-sWZVzHeVxIH3nNtXgkIS+PHvTIhDLA3CxrDSe5jz4XLaACPoK/dawojAd0Qet0zZ
-GfXk9Vm/5D0k/7MPkstOTAFCvfln2cdoYhA34WNkPW+uZNGBEdXTN3Tg/Oj8qAqV
-RdIXR8joIzgAJnCit1IDyTPHR88UNTlFtk4AJ9Ott4v1hmUOf3kBqB0owXj+fCpq
-3Mz7yL1DioePr8h7iw==
------END CERTIFICATE REQUEST-----
diff --git a/certs/CA/certreqs/bumper_req.txt b/certs/CA/certreqs/bumper_req.txt
deleted file mode 100644
index f59043e..0000000
--- a/certs/CA/certreqs/bumper_req.txt
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIIC0DCCAbgCAQAwETEPMA0GA1UEAwwGQnVtcGVyMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEA0eEqslnaJcbhqTalVMQTNT8/s6957rLSw78cZSVQEISN
-MwyS4Q5tYYJzXXEmqyp8rBMWAArfWGaPO8sgKs6rC9UcYurVr1GbxtsVdRRRI/fg
-tt2rtWQYdkBI7Dz9vjkcUF1tWwydWzPtKunzHGq9XNWY8NvJ4eq5dnO1oF1wyPWe
-5bbKURJpA3gOXuCtEY+TOv++8PK3vdPQnkE1pFRnTfBP5rmatnReFlbfxCUCwcnq
-X5a0+BeDanw4GSm4m0MCFXGWEb07P+8JUdUP+2rbMIZwUb42BBz/UKBeg410vgwh
-PISyQetW4XGn3bLJk933GFO6gvOU9CVdzPdxRPPLPQIDAQABoHoweAYJKoZIhvcN
-AQkOMWswaTAOBgNVHQ8BAf8EBAMCBaAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEG
-CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwJwYDVR0RBCAwHoINKi5lY291c2VyLm5l
-dIINKi5lY292YWNzLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAloHqI4fjQEL0H0I0
-TMr+DemH5GhYyVC7hs5bPfajqUbrQdTMvfUhfcUm0JgAmicKlAvVe1+75grkXeCF
-sfGBl10f5dbO9CEHBT9kzDJWhFT/ZFzGlblAwB6Kad7QGpIMKncJCZBUwkE4zrwO
-wEI1hAo0zvJr/SETte4YO9JianzT1Tu5f3nVgvKYVM+XJ0KZ7ReIdrT0Ev95mZhB
-tmZ1R7WeYtO8yZXVHP28uOHZcHCKgKcnrpb13yuNd6mkR643xMoirwp9t7xayJAt
-RnQgvb9o8HXNZoO1whr4ZF8gNs0MQGnT72MoV5E2KSZ9HMO4nQlzj9wIiEMls+ss
-UTUhBg==
------END CERTIFICATE REQUEST-----
-
diff --git a/certs/CA/certsdb/99BD46167599BDB4.pem b/certs/CA/certsdb/99BD46167599BDB4.pem
deleted file mode 100644
index a219c22..0000000
--- a/certs/CA/certsdb/99BD46167599BDB4.pem
+++ /dev/null
@@ -1,85 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 11078087720677522868 (0x99bd46167599bdb4)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Validity
- Not Before: Feb 1 05:59:32 2019 GMT
- Not After : Jan 29 05:59:32 2029 GMT
- Subject: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:aa:6e:af:15:99:3b:09:32:a1:a7:4b:ee:f7:13:
- 68:c1:94:4f:09:71:54:99:02:2d:27:c1:5f:16:2e:
- 45:d3:a6:44:24:fb:bd:f0:9b:a9:f6:6c:49:6f:09:
- 13:76:d6:5b:88:c2:fc:8b:8b:14:4c:39:df:8a:b5:
- 51:a8:83:c1:73:ca:aa:f1:b7:b4:38:e1:f0:91:35:
- be:6f:c6:99:7c:e1:ef:d9:c0:ee:d5:fb:f8:f5:0f:
- a7:96:b3:78:95:d6:2a:04:7d:3b:31:42:b6:33:c0:
- 36:2c:06:f1:6d:db:11:99:16:3e:77:c6:c6:df:ed:
- 95:40:b8:39:a2:82:40:fe:bb:f6:8b:63:0c:c6:96:
- ae:fd:3b:c7:79:a4:f5:5f:4e:83:87:27:33:bb:6f:
- cf:43:86:55:73:6c:0c:28:61:89:66:72:b3:90:3d:
- d8:54:53:6a:3a:57:76:01:05:58:ac:78:3d:0d:0a:
- 52:b4:b7:be:2b:4e:9a:6a:f4:f8:a2:3f:21:99:b6:
- b4:74:fb:d5:c0:23:7b:e8:51:f5:0a:ec:6a:11:4e:
- 9b:c3:f2:56:00:06:3b:58:e3:cf:67:b6:c3:26:50:
- 0e:f7:72:11:3f:39:2c:c9:b7:d5:69:1a:33:dc:8f:
- 81:66:c5:88:3f:c7:01:94:f0:3d:ac:aa:f3:a0:2a:
- e8:c7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
- X509v3 Authority Key Identifier:
- keyid:5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
- DirName:/C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
- serial:99:BD:46:16:75:99:BD:B4
-
- X509v3 Basic Constraints:
- CA:TRUE
- X509v3 Subject Alternative Name:
- email:null@null.com
- Signature Algorithm: sha1WithRSAEncryption
- 5e:45:c7:34:7f:9b:a4:6b:cc:3c:e7:34:84:76:ee:ec:98:be:
- 0f:de:ab:b2:a5:6d:59:18:eb:20:de:a4:fc:2c:4d:e4:9a:9c:
- 63:99:be:16:6a:1d:c0:57:73:e8:7f:9e:78:4d:2a:e6:11:a3:
- b6:57:18:84:6e:ae:a7:97:08:7e:1f:4d:33:fc:46:06:a7:d1:
- 6e:3a:d1:d9:ef:ba:fd:87:b8:e0:ea:51:85:d2:a6:de:49:e1:
- a6:43:d1:26:15:e2:f9:8b:8c:f0:94:fe:a3:62:dd:cc:ab:be:
- a5:dc:90:d8:28:0c:85:4b:fb:df:4a:f1:ac:35:86:7f:63:fd:
- ca:c6:aa:29:0b:b0:e1:e3:08:e6:4c:71:d2:08:32:c9:09:22:
- 6c:61:ec:87:49:8d:77:48:7a:f7:75:86:bb:4e:17:b0:fe:43:
- 4d:2f:95:bd:d5:0f:c1:ef:ba:f7:3e:e0:b6:2f:fa:4a:c9:45:
- 36:97:56:a4:6d:af:86:88:ff:98:2f:b2:e4:04:4d:c4:02:20:
- fc:66:8c:d5:2b:e9:5a:6c:1f:d2:67:34:c3:39:7e:f4:c7:37:
- 53:6b:11:99:a8:29:8b:3f:f6:3a:82:ae:f5:2c:d5:b7:23:88:
- bb:03:84:ad:cb:d0:f6:8d:24:9f:54:08:d1:39:da:1a:a9:f6:
- 1b:c9:53:65
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIJAJm9RhZ1mb20MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQKEwZCdW1wZXIxDzAN
-BgNVBAsTBkJ1bXBlcjEPMA0GA1UEAxMGQnVtcGVyMB4XDTE5MDIwMTA1NTkzMloX
-DTI5MDEyOTA1NTkzMlowVTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
-aWExDzANBgNVBAoTBkJ1bXBlcjEPMA0GA1UECxMGQnVtcGVyMQ8wDQYDVQQDEwZC
-dW1wZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqbq8VmTsJMqGn
-S+73E2jBlE8JcVSZAi0nwV8WLkXTpkQk+73wm6n2bElvCRN21luIwvyLixRMOd+K
-tVGog8Fzyqrxt7Q44fCRNb5vxpl84e/ZwO7V+/j1D6eWs3iV1ioEfTsxQrYzwDYs
-BvFt2xGZFj53xsbf7ZVAuDmigkD+u/aLYwzGlq79O8d5pPVfToOHJzO7b89DhlVz
-bAwoYYlmcrOQPdhUU2o6V3YBBViseD0NClK0t74rTppq9PiiPyGZtrR0+9XAI3vo
-UfUK7GoRTpvD8lYABjtY489ntsMmUA73chE/OSzJt9VpGjPcj4FmxYg/xwGU8D2s
-qvOgKujHAgMBAAGjgdIwgc8wHQYDVR0OBBYEFF45x3gxgzBRgtmIm3MLcu9EdHvV
-MIGFBgNVHSMEfjB8gBReOcd4MYMwUYLZiJtzC3LvRHR71aFZpFcwVTELMAkGA1UE
-BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAoTBkJ1bXBlcjEPMA0G
-A1UECxMGQnVtcGVyMQ8wDQYDVQQDEwZCdW1wZXKCCQCZvUYWdZm9tDAMBgNVHRME
-BTADAQH/MBgGA1UdEQQRMA+BDW51bGxAbnVsbC5jb20wDQYJKoZIhvcNAQEFBQAD
-ggEBAF5FxzR/m6RrzDznNIR27uyYvg/eq7KlbVkY6yDepPwsTeSanGOZvhZqHcBX
-c+h/nnhNKuYRo7ZXGIRurqeXCH4fTTP8Rgan0W460dnvuv2HuODqUYXSpt5J4aZD
-0SYV4vmLjPCU/qNi3cyrvqXckNgoDIVL+99K8aw1hn9j/crGqikLsOHjCOZMcdII
-MskJImxh7IdJjXdIevd1hrtOF7D+Q00vlb3VD8Hvuvc+4LYv+krJRTaXVqRtr4aI
-/5gvsuQETcQCIPxmjNUr6VpsH9JnNMM5fvTHN1NrEZmoKYs/9jqCrvUs1bcjiLsD
-hK3L0PaNJJ9UCNE52hqp9hvJU2U=
------END CERTIFICATE-----
diff --git a/certs/CA/certsdb/99BD46167599BDB5.pem b/certs/CA/certsdb/99BD46167599BDB5.pem
deleted file mode 100644
index 64ccbbf..0000000
--- a/certs/CA/certsdb/99BD46167599BDB5.pem
+++ /dev/null
@@ -1,85 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 11078087720677522869 (0x99bd46167599bdb5)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Validity
- Not Before: Feb 1 06:17:18 2019 GMT
- Not After : Jan 29 06:17:18 2029 GMT
- Subject: CN=Bumper
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d1:e1:2a:b2:59:da:25:c6:e1:a9:36:a5:54:c4:
- 13:35:3f:3f:b3:af:79:ee:b2:d2:c3:bf:1c:65:25:
- 50:10:84:8d:33:0c:92:e1:0e:6d:61:82:73:5d:71:
- 26:ab:2a:7c:ac:13:16:00:0a:df:58:66:8f:3b:cb:
- 20:2a:ce:ab:0b:d5:1c:62:ea:d5:af:51:9b:c6:db:
- 15:75:14:51:23:f7:e0:b6:dd:ab:b5:64:18:76:40:
- 48:ec:3c:fd:be:39:1c:50:5d:6d:5b:0c:9d:5b:33:
- ed:2a:e9:f3:1c:6a:bd:5c:d5:98:f0:db:c9:e1:ea:
- b9:76:73:b5:a0:5d:70:c8:f5:9e:e5:b6:ca:51:12:
- 69:03:78:0e:5e:e0:ad:11:8f:93:3a:ff:be:f0:f2:
- b7:bd:d3:d0:9e:41:35:a4:54:67:4d:f0:4f:e6:b9:
- 9a:b6:74:5e:16:56:df:c4:25:02:c1:c9:ea:5f:96:
- b4:f8:17:83:6a:7c:38:19:29:b8:9b:43:02:15:71:
- 96:11:bd:3b:3f:ef:09:51:d5:0f:fb:6a:db:30:86:
- 70:51:be:36:04:1c:ff:50:a0:5e:83:8d:74:be:0c:
- 21:3c:84:b2:41:eb:56:e1:71:a7:dd:b2:c9:93:dd:
- f7:18:53:ba:82:f3:94:f4:25:5d:cc:f7:71:44:f3:
- cb:3d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- X509v3 Subject Key Identifier:
- 26:7E:4F:14:80:43:9E:EF:64:C2:61:6E:81:68:4B:6A:F2:4E:B5:40
- X509v3 Authority Key Identifier:
- keyid:5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
-
- X509v3 Subject Alternative Name:
- DNS:*.ecouser.net, DNS:*.ecovacs.com
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage: critical
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha1WithRSAEncryption
- 89:11:41:18:ac:22:0d:4a:08:31:ee:18:d4:cf:88:02:93:f0:
- ef:53:f5:86:e1:b2:16:0e:8d:87:f9:e9:29:7a:aa:95:4e:d7:
- 89:96:ac:1c:9a:19:8c:84:62:41:7a:b8:8c:46:07:8f:56:ae:
- 18:31:52:cb:60:3f:01:57:4d:65:d6:5f:95:da:bc:c1:53:35:
- fa:cc:c6:49:aa:fe:35:d3:05:15:2c:bd:9b:ac:f0:36:d7:71:
- bc:ed:3e:f9:ac:c8:84:58:5e:f0:02:02:47:9c:0f:f3:f6:06:
- 35:4d:3b:69:2f:bb:81:cd:ae:61:84:75:97:b1:c2:e7:e1:74:
- 18:61:bc:c0:6b:2e:4d:f6:61:0d:36:72:3d:e2:ef:ef:e5:cf:
- 7a:17:af:d6:7c:d2:a4:88:ca:b3:4e:27:7e:f3:da:96:33:ef:
- 12:12:02:5a:31:70:82:e9:b6:e4:a9:57:d7:a4:b3:f6:3f:ea:
- fa:63:6a:e6:b7:26:73:bb:c1:87:4e:e2:13:40:65:b9:04:3c:
- c9:95:d7:8e:07:6f:9d:af:d2:36:ee:aa:5d:e5:f9:bb:cc:47:
- 9c:ce:62:cf:28:2e:a3:58:8b:63:a2:e3:c3:f4:b0:69:98:aa:
- 84:ff:a5:c2:52:8b:e8:b4:5c:2c:67:ef:63:b3:5c:42:95:6d:
- 6b:d7:5b:11
------BEGIN CERTIFICATE-----
-MIIDkzCCAnugAwIBAgIJAJm9RhZ1mb21MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQKEwZCdW1wZXIxDzAN
-BgNVBAsTBkJ1bXBlcjEPMA0GA1UEAxMGQnVtcGVyMB4XDTE5MDIwMTA2MTcxOFoX
-DTI5MDEyOTA2MTcxOFowETEPMA0GA1UEAwwGQnVtcGVyMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA0eEqslnaJcbhqTalVMQTNT8/s6957rLSw78cZSVQ
-EISNMwyS4Q5tYYJzXXEmqyp8rBMWAArfWGaPO8sgKs6rC9UcYurVr1GbxtsVdRRR
-I/fgtt2rtWQYdkBI7Dz9vjkcUF1tWwydWzPtKunzHGq9XNWY8NvJ4eq5dnO1oF1w
-yPWe5bbKURJpA3gOXuCtEY+TOv++8PK3vdPQnkE1pFRnTfBP5rmatnReFlbfxCUC
-wcnqX5a0+BeDanw4GSm4m0MCFXGWEb07P+8JUdUP+2rbMIZwUb42BBz/UKBeg410
-vgwhPISyQetW4XGn3bLJk933GFO6gvOU9CVdzPdxRPPLPQIDAQABo4GpMIGmMAkG
-A1UdEwQCMAAwHQYDVR0OBBYEFCZ+TxSAQ57vZMJhboFoS2ryTrVAMB8GA1UdIwQY
-MBaAFF45x3gxgzBRgtmIm3MLcu9EdHvVMCcGA1UdEQQgMB6CDSouZWNvdXNlci5u
-ZXSCDSouZWNvdmFjcy5jb20wDgYDVR0PAQH/BAQDAgWgMCAGA1UdJQEB/wQWMBQG
-CCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOCAQEAiRFBGKwiDUoI
-Me4Y1M+IApPw71P1huGyFg6Nh/npKXqqlU7XiZasHJoZjIRiQXq4jEYHj1auGDFS
-y2A/AVdNZdZfldq8wVM1+szGSar+NdMFFSy9m6zwNtdxvO0++azIhFhe8AICR5wP
-8/YGNU07aS+7gc2uYYR1l7HC5+F0GGG8wGsuTfZhDTZyPeLv7+XPehev1nzSpIjK
-s04nfvPaljPvEhICWjFwgum25KlX16Sz9j/q+mNq5rcmc7vBh07iE0BluQQ8yZXX
-jgdvna/SNu6qXeX5u8xHnM5izyguo1iLY6Ljw/SwaZiqhP+lwlKL6LRcLGfvY7Nc
-QpVta9dbEQ==
------END CERTIFICATE-----
diff --git a/certs/CA/index.txt b/certs/CA/index.txt
deleted file mode 100644
index 613826e..0000000
--- a/certs/CA/index.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-V 290129055932Z 99BD46167599BDB4 unknown /C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
-V 290129061718Z 99BD46167599BDB5 unknown /CN=Bumper
diff --git a/certs/CA/index.txt.attr b/certs/CA/index.txt.attr
deleted file mode 100644
index 8f7e63a..0000000
--- a/certs/CA/index.txt.attr
+++ /dev/null
@@ -1 +0,0 @@
-unique_subject = yes
diff --git a/certs/CA/index.txt.attr.old b/certs/CA/index.txt.attr.old
deleted file mode 100644
index 8f7e63a..0000000
--- a/certs/CA/index.txt.attr.old
+++ /dev/null
@@ -1 +0,0 @@
-unique_subject = yes
diff --git a/certs/CA/index.txt.old b/certs/CA/index.txt.old
deleted file mode 100644
index de82fa9..0000000
--- a/certs/CA/index.txt.old
+++ /dev/null
@@ -1 +0,0 @@
-V 290129055932Z 99BD46167599BDB4 unknown /C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
diff --git a/certs/CA/openssl.cnf b/certs/CA/openssl.cnf
deleted file mode 100644
index 77bb39a..0000000
--- a/certs/CA/openssl.cnf
+++ /dev/null
@@ -1,180 +0,0 @@
-HOME = .
-RANDFILE = $ENV::HOME/.rnd
-
-####################################################################
-# CA Definition
-[ ca ]
-default_ca = CA_default # The default ca section
-
-####################################################################
-# Per the above, this is where we define CA values
-[ CA_default ]
-
-dir = . # Where everything is kept
-certs = $dir/certsdb # Where the issued certs are kept
-new_certs_dir = $certs # default place for new certs.
-database = $dir/index.txt # database index file.
-certificate = $dir/cacert.pem # The CA certificate
-private_key = $dir/private/cakey.pem# The private key
-serial = $dir/serial # The current serial number
-RANDFILE = $dir/private/.rand # private random number file
-
-crldir = $dir/crl
-crlnumber = $dir/crlnumber # the current crl number
-crl = $crldir/crl.pem # The current CRL
-
-# By default we use "user certificate" extensions when signing
-x509_extensions = usr_cert # The extentions to add to the cert
-
-# Honor extensions requested of us
-copy_extensions = copy
-
-# Comment out the following two lines for the "traditional"
-# (and highly broken) format.
-name_opt = ca_default # Subject Name options
-cert_opt = ca_default # Certificate field options
-
-# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
-# so this is commented out by default to leave a V1 CRL.
-# crlnumber must also be commented out to leave a V1 CRL.
-#crl_extensions = crl_ext
-default_days = 3650 # how long to certify for
-default_crl_days= 30 # how long before next CRL
-default_md = sha1 # which md to use.
-preserve = no # keep passed DN ordering
-
-# A few difference way of specifying how similar the request should look
-# For type CA, the listed attributes must be the same, and the optional
-# and supplied fields are just that :-)
-policy = policy_anything
-
-####################################################################
-# The default policy for the CA when signing requests, requires some
-# resemblence to the CA cert
-#
-[ policy_match ]
-countryName = match # Must be the same as the CA
-stateOrProvinceName = match # Must be the same as the CA
-organizationName = match # Must be the same as the CA
-organizationalUnitName = optional # not required
-commonName = supplied # must be there, whatever it is
-emailAddress = optional # not required
-
-####################################################################
-# An alternative policy not referred to anywhere in this file. Can
-# be used by specifying '-policy policy_anything' to ca(8).
-#
-[ policy_anything ]
-countryName = optional
-stateOrProvinceName = optional
-localityName = optional
-organizationName = optional
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-####################################################################
-# This is where we define how to generate CSRs
-[ req ]
-default_bits = 2048
-default_keyfile = privkey.pem
-distinguished_name = req_distinguished_name # where to get DN for reqs
-attributes = req_attributes # req attributes
-x509_extensions = v3_ca # The extentions to add to self signed certs
-req_extensions = v3_req # The extensions to add to req's
-prompt = no
-
-# This sets a mask for permitted string types. There are several options.
-# default: PrintableString, T61String, BMPString.
-# pkix : PrintableString, BMPString.
-# utf8only: only UTF8Strings.
-# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
-# MASK:XXXX a literal mask value.
-# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
-# so use this option with caution!
-string_mask = nombstr
-
-
-####################################################################
-# Per "req" section, this is where we define DN info
-[ req_distinguished_name ]
-countryName = Country Name (2 letter code)
-countryName_default = US
-countryName_min = 2
-countryName_max = 2
-
-stateOrProvinceName = State or Province Name (full name)
-stateOrProvinceName_default = California
-
-localityName = Locality Name (eg, city)
-localityName_default = Hawthorne
-
-0.organizationName = Organization Name (eg, company)
-0.organizationName_default = PhilNet
-
-organizationalUnitName = Organizational Unit Name (eg, section)
-
-commonName = Common Name (eg, YOUR name)
-commonName_max = 64
-
-emailAddress = Email Address
-emailAddress_max = 64
-
-
-####################################################################
-# We don't want these, but the section must exist
-[ req_attributes ]
-#challengePassword = A challenge password
-#challengePassword_min = 4
-#challengePassword_max = 20
-#unstructuredName = An optional company name
-
-
-
-####################################################################
-[ v3_req ]
-keyUsage=critical,digitalSignature,keyEncipherment
-extendedKeyUsage=critical,serverAuth,clientAuth
-basicConstraints=critical,CA:false
-subjectAltName = @alt_names
-[ alt_names ]
-DNS.0 = *.ecouser.net
-DNS.1 = *.ecovacs.com
-
-####################################################################
-# Extensions for when we sign normal certs (specified as default)
-[ usr_cert ]
-basicConstraints = CA:false
-subjectKeyIdentifier = hash
-authorityKeyIdentifier = keyid,issuer
-subjectAltName = @alt_names
-[ alt_names ]
-DNS.0 = *.ecouser.net
-DNS.1 = *.ecovacs.com
-
-####################################################################
-# Same as above, but cert req already has SubjectAltName
-[ usr_cert_has_san ]
-basicConstraints = CA:false
-subjectKeyIdentifier = hash
-authorityKeyIdentifier = keyid,issuer
-subjectAltName = @alt_names
-[ alt_names ]
-DNS.0 = *.ecouser.net
-DNS.1 = *.ecovacs.com
-
-####################################################################
-# Extensions to use when signing a CA
-[ v3_ca ]
-subjectKeyIdentifier = hash
-authorityKeyIdentifier = keyid:always,issuer:always
-basicConstraints = CA:true
-subjectAltName=email:move
-
-####################################################################
-# Same as above, but CA req already has SubjectAltName
-[ v3_ca_has_san ]
-subjectKeyIdentifier = hash
-authorityKeyIdentifier = keyid:always,issuer:always
-basicConstraints = CA:true
-
diff --git a/certs/CA/private/cakey.pem b/certs/CA/private/cakey.pem
deleted file mode 100644
index fd39a20..0000000
--- a/certs/CA/private/cakey.pem
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIzLScD02ODzQCAggA
-MB0GCWCGSAFlAwQBKgQQzjzZ8LiXuLxb/Rx75kGXkwSCBNAmHUh4RTgy1bJmwZN7
-uyb4gGHtY9+ZvKZikibq7LpiwmDAwjjwguJz/HRsquq8fsZDpB+rV4hD4lB3lHuj
-jqETzKst5qLTgP0cC9BS0S0P9f0/L7MEcwtiBkds6dVs4Ot6IDr4napC+6wQCBfr
-ISrTN8+ls9IVghiS1eOrarFTy2ZxkXFM6PJczLd15/pbTm91etLWl1vnPCJn3MTc
-vUvneAChKFiwaX4Cbx8bhQP11OBBNshM1zANSoGAdijRpvRCGfeOIvgLsbBl9N0d
-+lV6iJR0TzOr4GquBDXor/y2Mofn6wYRwtSLRUgHgAxy1USosWVuXwrtGO4htPoR
-aGt8V3h4XQ90VGAh6ez43/nmkVDgIj8VU9qZ+skCz7Y4TxPZYXUIcnG14KFj9lsk
-r+uV6HmHyBKSlSkAE+D9uukQb71oIW83tsSn6I4ulcWaax6VsOS5n/Jrhf9V+Nz0
-e0CjrOJeLUSd2vTiyz03ho32nIrsGFeNDHhFmKzXNynjcW3z6Mx9/dSjqPHn8wFn
-0dcVkq0GAZ+L8woNyDhr4e7Hhy6FEDhRX9bWz7FlswnBzym2AzU/zhagDrP2MIQ9
-o/cjAp3AoX70IIF7kIha8OXG4ew4tHpQIAj9E5SG5uEeD6gVTg7HB93dH+NEeLNR
-F65wzQHPhf+V2zR7qlpCg3gqzyE9mvvTN/DMAJwASXWXK37ITIjcXhErH/2shHSK
-jRwYuQiAWuhPrAr04EUoeHQFM6EAKDqBsFRr+/Ot34DqhAwAOlmkyCM/mw7IDl73
-pX/Ey9CQc2u2PS0zqYkDIzWE1Osek3FIF6JHSzaiRYODjaE6v15FLe7hZ56x6NMI
-EDzpScp6HwMg6jsudbONrz3KwvXE6j4+yWpp8tgkZzwsIfnOMtWSrGgX4Oz9Y0Ep
-jZ1yKDLQBjKZor2z4FBNze74tEnzJdBl59mQoN3ffFWHRlnkOhAZ+HsaXoIKB6AZ
-3NPzlgGhOmtza6HKAwlseMgjpNH7EmeTLplr5nUlEMwwJ2+i8VGS4J9458vipcBm
-50MbqaR8N8jAsanxyAbBF7gLPzsezN9Kzus99B6uB2nZIgZIsOeCeBLEZGzz9bUv
-AiI3rM38nFkkKeHjJwqcYsO6LiLxdstnaHSveE7d6ugmN3+bNaZ+QCUDFlfELr4M
-n5Eiwv3+hlCL8UBubacdQypfYvYI/z8rTdH+5eTVxBjeTCG0QmjDlYiuHcycL+q3
-iE3WxQ0yGpeJL6V985Ej/0SHkudTI49T5o+jcp6HFNS7xQelBGndpXGq9Xyc+OV/
-c+1zYWxz/sMFAbMkCF2pMMLfKL5EBkLBCpOdxHtWFt9JMxuhRfl3YzN81xSV1m0A
-FtURjPUSwGqI7QFPl4R4MA1+0AdveZYprGo2nSUQpSoCW9WHl8U8tLIUNtew1MPA
-v19h5DSqJ3tj+pPdxmFixoG+hBNk8FO1lJvH6P2an6lYVTlZ3/uDU5/DHTUTHuen
-9x8FY3LQDQZA65QEnN092cUxXWw6cha+xXvwrwZGZiWXtuMBh/mfa4apxQ5+KY0N
-/RCbIBctvLgijuC+xQw8GqBcG5L7urCOhnyZCXspWW7+loI7uZ0EfpNi7jY8BmAs
-3S3MwMwwp+uvloikg3ZTUJmx/g==
------END ENCRYPTED PRIVATE KEY-----
diff --git a/certs/CA/private/key.pem b/certs/CA/private/key.pem
deleted file mode 100644
index f3ece38..0000000
--- a/certs/CA/private/key.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR4SqyWdolxuGp
-NqVUxBM1Pz+zr3nustLDvxxlJVAQhI0zDJLhDm1hgnNdcSarKnysExYACt9YZo87
-yyAqzqsL1Rxi6tWvUZvG2xV1FFEj9+C23au1ZBh2QEjsPP2+ORxQXW1bDJ1bM+0q
-6fMcar1c1Zjw28nh6rl2c7WgXXDI9Z7ltspREmkDeA5e4K0Rj5M6/77w8re909Ce
-QTWkVGdN8E/muZq2dF4WVt/EJQLByepflrT4F4NqfDgZKbibQwIVcZYRvTs/7wlR
-1Q/7atswhnBRvjYEHP9QoF6DjXS+DCE8hLJB61bhcafdssmT3fcYU7qC85T0JV3M
-93FE88s9AgMBAAECggEBAJ4N3aOWeuv8DDDsUDG3v2dYDFb7DO4viP2UzIN3SAZI
-bDVHgM0vmjvWi56Q+bfpNR44+VZq2auvAKrc24qhPLqacNglVWrEIHXuwwf6luhp
-YbcU1JyzlqBm5QPTIpvAUoxK73Gj3FS0lCS/Li/2SkjBKn4oZq5Vn/mORfdQpwEO
-aY5YzNNCzCwbqL/XcwvN1XRpF9puhBb+o2TtfGPLBf5LiScJWxrtPM7q+dFG/Ef7
-f9L28iX+W6e3lD0/d93XEtlh1IsaZTWkl4m01Etg0f2FFtcja38eG+Yys4YNSpPe
-VUWtFL2eDX+u5wv7nbaG9GsZmithXL6xa0PdwOd0KAECgYEA/D7K2KcxS+HeBgcG
-V3b0m6QH1bRbqRxzK22TKnCVLAlRW7+5bfK56sHqMrOnDp/PuyAdq93roeJBNnAg
-DrUt9i/lFTZ2kSBTJIlKW7cHv2Hocw3sQSDY/PhAXtALULxa8NHadPGsntHQDLzq
-TVUNhOU6+GqPcqTp8BeSy+XrGD0CgYEA1QDvbxh/5tQxCFXcKn5KQCpJhbCfKBSW
-drd8YF3Gdpxt3d2vTFTOsQ3xyAvEhSV0Jy9WUXobmx+KK8OjZqsR4PoYpYN3IWIW
-N9jBKE9bahPRFF3g3FxaeVrCBkZBVK+ZAv/E5gshCyCXOmgHT+Kgi1Xpb4X0J/Pj
-T83O7y/DrwECgYEAlagfq4kOy2m307WpQo12NT2N1HIMi/owLoz1apGfP6BLn/bR
-anU/bxQcAnbqX9fbZLd6QzUIj2Rwsn611mQSX+Ussng8wn/+NEgsUNv4AclyI4kY
-Kc/2TahwcJBYlk8aWZT4WrfkZdov6M7Q6I7U1Ys3gJmggDFuBp/F3amM4TUCgYBv
-IofKvUuukjPrF3FCMpZnGCk4Ockwzl0bH+0jEoqERGYGhq35853MP2xRZeJpXftW
-npo49K8GptQetXrCDKvNaHAHm6pCnrzc8pkFgTI/DIvgRoMWNpF2E+Z8A5f+qYf6
-SpzfMhtRhPWiobh+8820JWUgrRGQ7u1BLC62GYPOAQKBgG/rt2Xu42DJcQ/wm7wN
-LB8zn54G/rKWq+mXQbenpr1lN4zBOGgZILrRb1HTcQ7a19056BHBmx3J52yQAnGH
-cxuhOyppsH3WgUkUqYN4bzO1CJorX3cP9udBAcmN4BWLF7pLgT7zHrLkJg05sWnd
-UHWm2y7vdXeTvdD381p0Ug0S
------END PRIVATE KEY-----
diff --git a/certs/CA/serial b/certs/CA/serial
deleted file mode 100644
index 3bf84d2..0000000
--- a/certs/CA/serial
+++ /dev/null
@@ -1 +0,0 @@
-99BD46167599BDB6
diff --git a/certs/CA/serial.old b/certs/CA/serial.old
deleted file mode 100644
index 9d0f0bc..0000000
--- a/certs/CA/serial.old
+++ /dev/null
@@ -1 +0,0 @@
-99BD46167599BDB5
diff --git a/certs/README.md b/certs/README.md
new file mode 100644
index 0000000..9881855
--- /dev/null
+++ b/certs/README.md
@@ -0,0 +1,3 @@
+# Certs Directory
+
+Place your created certs in this directory
diff --git a/certs/cert.pem b/certs/cert.pem
deleted file mode 100644
index 64ccbbf..0000000
--- a/certs/cert.pem
+++ /dev/null
@@ -1,85 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 11078087720677522869 (0x99bd46167599bdb5)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=US, ST=California, O=Bumper, OU=Bumper, CN=Bumper
- Validity
- Not Before: Feb 1 06:17:18 2019 GMT
- Not After : Jan 29 06:17:18 2029 GMT
- Subject: CN=Bumper
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d1:e1:2a:b2:59:da:25:c6:e1:a9:36:a5:54:c4:
- 13:35:3f:3f:b3:af:79:ee:b2:d2:c3:bf:1c:65:25:
- 50:10:84:8d:33:0c:92:e1:0e:6d:61:82:73:5d:71:
- 26:ab:2a:7c:ac:13:16:00:0a:df:58:66:8f:3b:cb:
- 20:2a:ce:ab:0b:d5:1c:62:ea:d5:af:51:9b:c6:db:
- 15:75:14:51:23:f7:e0:b6:dd:ab:b5:64:18:76:40:
- 48:ec:3c:fd:be:39:1c:50:5d:6d:5b:0c:9d:5b:33:
- ed:2a:e9:f3:1c:6a:bd:5c:d5:98:f0:db:c9:e1:ea:
- b9:76:73:b5:a0:5d:70:c8:f5:9e:e5:b6:ca:51:12:
- 69:03:78:0e:5e:e0:ad:11:8f:93:3a:ff:be:f0:f2:
- b7:bd:d3:d0:9e:41:35:a4:54:67:4d:f0:4f:e6:b9:
- 9a:b6:74:5e:16:56:df:c4:25:02:c1:c9:ea:5f:96:
- b4:f8:17:83:6a:7c:38:19:29:b8:9b:43:02:15:71:
- 96:11:bd:3b:3f:ef:09:51:d5:0f:fb:6a:db:30:86:
- 70:51:be:36:04:1c:ff:50:a0:5e:83:8d:74:be:0c:
- 21:3c:84:b2:41:eb:56:e1:71:a7:dd:b2:c9:93:dd:
- f7:18:53:ba:82:f3:94:f4:25:5d:cc:f7:71:44:f3:
- cb:3d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- X509v3 Subject Key Identifier:
- 26:7E:4F:14:80:43:9E:EF:64:C2:61:6E:81:68:4B:6A:F2:4E:B5:40
- X509v3 Authority Key Identifier:
- keyid:5E:39:C7:78:31:83:30:51:82:D9:88:9B:73:0B:72:EF:44:74:7B:D5
-
- X509v3 Subject Alternative Name:
- DNS:*.ecouser.net, DNS:*.ecovacs.com
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage: critical
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha1WithRSAEncryption
- 89:11:41:18:ac:22:0d:4a:08:31:ee:18:d4:cf:88:02:93:f0:
- ef:53:f5:86:e1:b2:16:0e:8d:87:f9:e9:29:7a:aa:95:4e:d7:
- 89:96:ac:1c:9a:19:8c:84:62:41:7a:b8:8c:46:07:8f:56:ae:
- 18:31:52:cb:60:3f:01:57:4d:65:d6:5f:95:da:bc:c1:53:35:
- fa:cc:c6:49:aa:fe:35:d3:05:15:2c:bd:9b:ac:f0:36:d7:71:
- bc:ed:3e:f9:ac:c8:84:58:5e:f0:02:02:47:9c:0f:f3:f6:06:
- 35:4d:3b:69:2f:bb:81:cd:ae:61:84:75:97:b1:c2:e7:e1:74:
- 18:61:bc:c0:6b:2e:4d:f6:61:0d:36:72:3d:e2:ef:ef:e5:cf:
- 7a:17:af:d6:7c:d2:a4:88:ca:b3:4e:27:7e:f3:da:96:33:ef:
- 12:12:02:5a:31:70:82:e9:b6:e4:a9:57:d7:a4:b3:f6:3f:ea:
- fa:63:6a:e6:b7:26:73:bb:c1:87:4e:e2:13:40:65:b9:04:3c:
- c9:95:d7:8e:07:6f:9d:af:d2:36:ee:aa:5d:e5:f9:bb:cc:47:
- 9c:ce:62:cf:28:2e:a3:58:8b:63:a2:e3:c3:f4:b0:69:98:aa:
- 84:ff:a5:c2:52:8b:e8:b4:5c:2c:67:ef:63:b3:5c:42:95:6d:
- 6b:d7:5b:11
------BEGIN CERTIFICATE-----
-MIIDkzCCAnugAwIBAgIJAJm9RhZ1mb21MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQKEwZCdW1wZXIxDzAN
-BgNVBAsTBkJ1bXBlcjEPMA0GA1UEAxMGQnVtcGVyMB4XDTE5MDIwMTA2MTcxOFoX
-DTI5MDEyOTA2MTcxOFowETEPMA0GA1UEAwwGQnVtcGVyMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA0eEqslnaJcbhqTalVMQTNT8/s6957rLSw78cZSVQ
-EISNMwyS4Q5tYYJzXXEmqyp8rBMWAArfWGaPO8sgKs6rC9UcYurVr1GbxtsVdRRR
-I/fgtt2rtWQYdkBI7Dz9vjkcUF1tWwydWzPtKunzHGq9XNWY8NvJ4eq5dnO1oF1w
-yPWe5bbKURJpA3gOXuCtEY+TOv++8PK3vdPQnkE1pFRnTfBP5rmatnReFlbfxCUC
-wcnqX5a0+BeDanw4GSm4m0MCFXGWEb07P+8JUdUP+2rbMIZwUb42BBz/UKBeg410
-vgwhPISyQetW4XGn3bLJk933GFO6gvOU9CVdzPdxRPPLPQIDAQABo4GpMIGmMAkG
-A1UdEwQCMAAwHQYDVR0OBBYEFCZ+TxSAQ57vZMJhboFoS2ryTrVAMB8GA1UdIwQY
-MBaAFF45x3gxgzBRgtmIm3MLcu9EdHvVMCcGA1UdEQQgMB6CDSouZWNvdXNlci5u
-ZXSCDSouZWNvdmFjcy5jb20wDgYDVR0PAQH/BAQDAgWgMCAGA1UdJQEB/wQWMBQG
-CCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOCAQEAiRFBGKwiDUoI
-Me4Y1M+IApPw71P1huGyFg6Nh/npKXqqlU7XiZasHJoZjIRiQXq4jEYHj1auGDFS
-y2A/AVdNZdZfldq8wVM1+szGSar+NdMFFSy9m6zwNtdxvO0++azIhFhe8AICR5wP
-8/YGNU07aS+7gc2uYYR1l7HC5+F0GGG8wGsuTfZhDTZyPeLv7+XPehev1nzSpIjK
-s04nfvPaljPvEhICWjFwgum25KlX16Sz9j/q+mNq5rcmc7vBh07iE0BluQQ8yZXX
-jgdvna/SNu6qXeX5u8xHnM5izyguo1iLY6Ljw/SwaZiqhP+lwlKL6LRcLGfvY7Nc
-QpVta9dbEQ==
------END CERTIFICATE-----
diff --git a/certs/key.pem b/certs/key.pem
deleted file mode 100644
index f3ece38..0000000
--- a/certs/key.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR4SqyWdolxuGp
-NqVUxBM1Pz+zr3nustLDvxxlJVAQhI0zDJLhDm1hgnNdcSarKnysExYACt9YZo87
-yyAqzqsL1Rxi6tWvUZvG2xV1FFEj9+C23au1ZBh2QEjsPP2+ORxQXW1bDJ1bM+0q
-6fMcar1c1Zjw28nh6rl2c7WgXXDI9Z7ltspREmkDeA5e4K0Rj5M6/77w8re909Ce
-QTWkVGdN8E/muZq2dF4WVt/EJQLByepflrT4F4NqfDgZKbibQwIVcZYRvTs/7wlR
-1Q/7atswhnBRvjYEHP9QoF6DjXS+DCE8hLJB61bhcafdssmT3fcYU7qC85T0JV3M
-93FE88s9AgMBAAECggEBAJ4N3aOWeuv8DDDsUDG3v2dYDFb7DO4viP2UzIN3SAZI
-bDVHgM0vmjvWi56Q+bfpNR44+VZq2auvAKrc24qhPLqacNglVWrEIHXuwwf6luhp
-YbcU1JyzlqBm5QPTIpvAUoxK73Gj3FS0lCS/Li/2SkjBKn4oZq5Vn/mORfdQpwEO
-aY5YzNNCzCwbqL/XcwvN1XRpF9puhBb+o2TtfGPLBf5LiScJWxrtPM7q+dFG/Ef7
-f9L28iX+W6e3lD0/d93XEtlh1IsaZTWkl4m01Etg0f2FFtcja38eG+Yys4YNSpPe
-VUWtFL2eDX+u5wv7nbaG9GsZmithXL6xa0PdwOd0KAECgYEA/D7K2KcxS+HeBgcG
-V3b0m6QH1bRbqRxzK22TKnCVLAlRW7+5bfK56sHqMrOnDp/PuyAdq93roeJBNnAg
-DrUt9i/lFTZ2kSBTJIlKW7cHv2Hocw3sQSDY/PhAXtALULxa8NHadPGsntHQDLzq
-TVUNhOU6+GqPcqTp8BeSy+XrGD0CgYEA1QDvbxh/5tQxCFXcKn5KQCpJhbCfKBSW
-drd8YF3Gdpxt3d2vTFTOsQ3xyAvEhSV0Jy9WUXobmx+KK8OjZqsR4PoYpYN3IWIW
-N9jBKE9bahPRFF3g3FxaeVrCBkZBVK+ZAv/E5gshCyCXOmgHT+Kgi1Xpb4X0J/Pj
-T83O7y/DrwECgYEAlagfq4kOy2m307WpQo12NT2N1HIMi/owLoz1apGfP6BLn/bR
-anU/bxQcAnbqX9fbZLd6QzUIj2Rwsn611mQSX+Ussng8wn/+NEgsUNv4AclyI4kY
-Kc/2TahwcJBYlk8aWZT4WrfkZdov6M7Q6I7U1Ys3gJmggDFuBp/F3amM4TUCgYBv
-IofKvUuukjPrF3FCMpZnGCk4Ockwzl0bH+0jEoqERGYGhq35853MP2xRZeJpXftW
-npo49K8GptQetXrCDKvNaHAHm6pCnrzc8pkFgTI/DIvgRoMWNpF2E+Z8A5f+qYf6
-SpzfMhtRhPWiobh+8820JWUgrRGQ7u1BLC62GYPOAQKBgG/rt2Xu42DJcQ/wm7wN
-LB8zn54G/rKWq+mXQbenpr1lN4zBOGgZILrRb1HTcQ7a19056BHBmx3J52yQAnGH
-cxuhOyppsH3WgUkUqYN4bzO1CJorX3cP9udBAcmN4BWLF7pLgT7zHrLkJg05sWnd
-UHWm2y7vdXeTvdD381p0Ug0S
------END PRIVATE KEY-----
diff --git a/create_certs/Bumper_SAN.txt b/create_certs/Bumper_SAN.txt
new file mode 100644
index 0000000..9994fc3
--- /dev/null
+++ b/create_certs/Bumper_SAN.txt
@@ -0,0 +1,6 @@
+ecovacs.com
+*.ecovacs.com
+ecouser.net
+*.ecouser.net
+ecovacs.net
+*.ecovacs.net
\ No newline at end of file
diff --git a/create_certs/create_certs_linux b/create_certs/create_certs_linux
new file mode 100755
index 0000000..e809faa
Binary files /dev/null and b/create_certs/create_certs_linux differ
diff --git a/create_certs/create_certs_osx b/create_certs/create_certs_osx
new file mode 100755
index 0000000..c985f63
Binary files /dev/null and b/create_certs/create_certs_osx differ
diff --git a/create_certs/create_certs_rpi b/create_certs/create_certs_rpi
new file mode 100755
index 0000000..c678ef0
Binary files /dev/null and b/create_certs/create_certs_rpi differ
diff --git a/create_certs/create_certs_windows.exe b/create_certs/create_certs_windows.exe
new file mode 100755
index 0000000..18bfa69
Binary files /dev/null and b/create_certs/create_certs_windows.exe differ
diff --git a/create_certs/src/build.sh b/create_certs/src/build.sh
new file mode 100755
index 0000000..03e85bb
--- /dev/null
+++ b/create_certs/src/build.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+SCRIPTPATH=$(dirname "$BASH_SOURCE")
+OUTPUTPATH=$(dirname $(dirname "$BASH_SOURCE"))
+echo "Building for Windows: $OUTPUTPATH/create_certs_windows.exe"
+GOOS=windows go build -o $OUTPUTPATH/create_certs_windows.exe $SCRIPTPATH/create_certs.go
+echo "Building for OSX $OUTPUTPATH/create_certs_osx"
+GOOS=darwin go build -o $OUTPUTPATH/create_certs_osx $SCRIPTPATH/create_certs.go
+echo "Building for Linux $OUTPUTPATH/create_certs_linux"
+GOOS=linux go build -o $OUTPUTPATH/create_certs_linux $SCRIPTPATH/create_certs.go
+echo "Building for ARM (Raspberry Pi) $OUTPUTPATH/create_certs_rpi"
+GOOS=linux GOARCH=arm GOARM=5 go build -o $OUTPUTPATH/create_certs_rpi $SCRIPTPATH/create_certs.go
+echo "Build Complete"
\ No newline at end of file
diff --git a/create_certs/src/create_certs.go b/create_certs/src/create_certs.go
new file mode 100644
index 0000000..5eaa1a8
--- /dev/null
+++ b/create_certs/src/create_certs.go
@@ -0,0 +1,193 @@
+package main
+
+import (
+ "bufio"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "log"
+ "math/big"
+ "net"
+ "os"
+ "time"
+)
+
+func main() {
+
+ make_CA()
+
+ signCert()
+}
+
+func make_CA() {
+ priv, _ := rsa.GenerateKey(rand.Reader, 2048)
+ pub := &priv.PublicKey
+
+ ca := &x509.Certificate{
+ SerialNumber: big.NewInt(1653),
+ Subject: pkix.Name{
+ CommonName: string("Bumper CA"),
+ Organization: []string{"Bumper"},
+ },
+ NotBefore: time.Now(),
+ NotAfter: time.Now().AddDate(10, 0, 0),
+ SubjectKeyId: bigIntHash(priv.N),
+ AuthorityKeyId: bigIntHash(priv.N),
+ KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
+ ExtKeyUsage: []x509.ExtKeyUsage{},
+ IsCA: true,
+ BasicConstraintsValid: true,
+ MaxPathLen: -1,
+ }
+
+ ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
+ if err != nil {
+ log.Println("create ca failed", err)
+ return
+ }
+
+ // Public key
+ certOut, err := os.Create("ca.crt")
+ if err != nil {
+ log.Fatal("create ca.crt failed", err)
+ }
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: ca_b})
+ certOut.Close()
+ log.Print("ca.crt created\n")
+
+ // Private key
+ keyOut, err := os.OpenFile("ca.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatal("create ca.key failed", err)
+ }
+ pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
+ keyOut.Close()
+ log.Print("ca.key created\n")
+}
+
+func signCert() {
+
+ // Load CA
+ catls, err := tls.LoadX509KeyPair("ca.crt", "ca.key")
+ if err != nil {
+ log.Fatal("error loading ca cert", err)
+ }
+
+ ca, err := x509.ParseCertificate(catls.Certificate[0])
+ if err != nil {
+ log.Fatal("error parsing ca cert", err)
+ }
+
+ hostname, _ := os.Hostname()
+ ifaces, err := net.Interfaces()
+ var ips []net.IP
+ // handle err
+ for _, i := range ifaces {
+ addrs, _ := i.Addrs()
+ // handle err
+ for _, addr := range addrs {
+ var ip net.IP
+ switch v := addr.(type) {
+ case *net.IPNet:
+ ip = v.IP
+ case *net.IPAddr:
+ ip = v.IP
+ }
+ ips = append(ips, ip)
+ // process IP address
+ }
+ }
+ ips = append(ips, net.ParseIP("127.0.0.1"))
+
+ privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
+ pubKey := &privateKey.PublicKey
+
+ //DNS/SAN names for cert
+ dnsNames := []string{hostname, "localhost"}
+ //Read SANs from file
+ if fileExists("Bumper_SAN.txt") {
+ sans, err := readLines("Bumper_SAN.txt")
+ if err != nil {
+ log.Fatalf("readLines: %s", err)
+ }
+ dnsNames = append(dnsNames, sans...)
+ }
+
+ // Prepare certificate
+ template := x509.Certificate{
+ SerialNumber: big.NewInt(1658),
+ Issuer: ca.Subject,
+ Subject: pkix.Name{
+ CommonName: "Bumper Server",
+ Organization: []string{"Bumper"},
+ },
+ SubjectKeyId: bigIntHash(privateKey.N),
+ AuthorityKeyId: ca.RawSubject,
+ NotBefore: time.Now(),
+ NotAfter: time.Now().AddDate(10, 0, 0),
+ IsCA: false,
+ BasicConstraintsValid: true,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
+ KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
+ DNSNames: dnsNames,
+ IPAddresses: ips,
+ }
+
+ // Sign the certificate
+ cert_b, err := x509.CreateCertificate(rand.Reader, &template, ca, pubKey, catls.PrivateKey)
+
+ // Public key
+ certOut, err := os.Create("bumper.crt")
+ if err != nil {
+ log.Fatal("create bumper.crt failed", err)
+ }
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cert_b})
+ certOut.Close()
+ log.Print("bumper.crt created\n")
+
+ // Private key
+ keyOut, err := os.OpenFile("bumper.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatal("create bumper.key failed", err)
+ }
+ pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
+ keyOut.Close()
+ log.Print("bumper.key created\n")
+}
+
+func bigIntHash(n *big.Int) []byte {
+ h := sha1.New()
+ h.Write(n.Bytes())
+ return h.Sum(nil)
+}
+
+// readLines reads a whole file into memory
+// and returns a slice of its lines.
+func readLines(path string) ([]string, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var lines []string
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ lines = append(lines, scanner.Text())
+ }
+ return lines, scanner.Err()
+}
+
+// fileExists checks if a file exists and is not a directory before we
+// try using it to prevent further errors.
+func fileExists(filename string) bool {
+ info, err := os.Stat(filename)
+ if os.IsNotExist(err) {
+ return false
+ }
+ return !info.IsDir()
+}
diff --git a/data/README.md b/data/README.md
new file mode 100644
index 0000000..d7e7d7d
--- /dev/null
+++ b/data/README.md
@@ -0,0 +1,3 @@
+# Data Directory
+
+Where Bumper executes persistent data will be stored here (bumper.db)
diff --git a/docs/Create_Certs.md b/docs/Create_Certs.md
new file mode 100644
index 0000000..e3e5391
--- /dev/null
+++ b/docs/Create_Certs.md
@@ -0,0 +1,163 @@
+# Creating Certs
+
+Bumper requires specially crafted certificates to work properly. In the spirit of security, Bumper will not ship with default certificates. Users will need to generate and provide their own certificates.
+
+Certificates should be placed in the `{bumper_home}/certs` directory. If certificates are located elsewhere [environment variables](Env_Var.md) can be set that point to their location.
+
+Users can generate certificates in the following ways:
+
+| Method | Description |
+| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
+| [Create_Certs](#creating-certs-using-createcerts) | ***(Preferred)*** This is a utility that has been created to assist in generating the certificates required easily. |
+| [OpenSSL](#manually-create-certs-with-openssl) | Users can manually create the same certificates as Create_Certs by utilizing OpenSSL. |
+| [Custom CA/Self](#using-a-custom-caself) | If a user has their own CA the certificates can be generated there and used within Bumper. |
+
+**Certificate Requirements:**
+
+* A CA Cert must be provided that can be imported into devices (phones, browsers, etc).
+* Server certificate should include [SANs (Subject Alternate Names)](#subject-alternative-name) for all of the *.ecovacs, etc domains.
+
+## Creating certs using Create_Certs
+
+Create_Certs was created to ease creation of certificates specifically for Bumper. Binaries are provided for Windows/Linux/OSX/RPi (ARMv5) in the Create_Certs directory.
+
+| Binary | Platform |
+| ------------------------ | -------------------- |
+| create_certs_linux | Linux |
+| create_certs_osx | macOS/x |
+| create_certs_windows.exe | Windows |
+| create_certs_rpi | RaspberryPi (ARM v5) |
+
+Create_Certs is written in Go which allows cross-platform compiling. If the binaries don't work on your platform, install Go.
+
+With Go installed you can:
+* Execute the go code - `go run create_certs/src/create_certs.go`
+* Build a new binary for your platform - `go build create_certs/src/create_certs.go`
+
+### Usage
+
+Create_Certs will automatically create the required certificates in the directory it is executed from. For best results change to the {bumper_home}/certs directory prior to executing, otherwise you'll need to move the certs after.
+
+1. `cd certs`
+2. Execute create_certs (using the binary fitting your platform) - `../create_certs/create_certs_{platform}`
+3. The certificates are generated and should be available in the current directory (certs)
+
+## Subject Alternative Name
+
+The server certificate requires a number of SAN (Subject Alternative Names) be added. Create_Certs handles this automatically by loading any SANs listed in the `create_certs/Bumper_SAN.txt` file. If creating certificates manually via OpenSSl/Custom CA these will need to be added.
+
+## Manually create certs with OpenSSL
+
+I get it, you don't trust create_certs and want to do it manually. The easiest way to create the required certs is at https://certificatetools.com/. In fact the below OpenSSL commands come straight from that site, post creation via the GUI.
+
+### Create a Root CA
+
+1. Create csrconfig.txt for use in later commands
+ csrconfig.txt
+ ````
+ [ req ]
+ default_md = sha256
+ prompt = no
+ req_extensions = req_ext
+ distinguished_name = req_distinguished_name
+ [ req_distinguished_name ]
+ commonName = Bumper CA
+ organizationName = Bumper
+ [ req_ext ]
+ keyUsage=critical,keyCertSign,cRLSign
+ basicConstraints=critical,CA:true,pathlen:1
+ ````
+
+1. Create certconfig.txt for use in later commands
+ certconfig.txt
+ ````
+ [ req ]
+ default_md = sha256
+ prompt = no
+ req_extensions = req_ext
+ distinguished_name = req_distinguished_name
+ [ req_distinguished_name ]
+ commonName = Bumper CA
+ organizationName = Bumper
+ [ req_ext ]
+ subjectKeyIdentifier = hash
+ authorityKeyIdentifier = keyid:always,issuer
+ keyUsage=critical,keyCertSign,cRLSign
+ basicConstraints=critical,CA:true,pathlen:1
+ ````
+
+1. Generate the RSA private key
+`openssl genpkey -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out priv.key`
+
+1. Create the CSR
+`openssl req -new -nodes -key priv.key -config csrconfig.txt -out cert.csr`
+
+1. Self-sign your CSR
+`openssl req -x509 -nodes -in cert.csr -days 3650 -key priv.key -config certconfig.txt -extensions req_ext -out cert.crt`
+
+### Create the Server Certificate
+
+1. Create csrconfig.txt for use in later commands
+ csrconfig.txt
+ ````
+ [ req ]
+ default_md = sha256
+ prompt = no
+ req_extensions = req_ext
+ distinguished_name = req_distinguished_name
+ [ req_distinguished_name ]
+ commonName = Bumper Server
+ organizationName = Bumper
+ [ req_ext ]
+ keyUsage=critical,digitalSignature,keyEncipherment
+ extendedKeyUsage=serverAuth,clientAuth
+ basicConstraints=critical,CA:false
+ subjectAltName = @alt_names
+ [ alt_names ]
+ DNS.0 = ecovacs.com
+ DNS.1 = *.ecovacs.com
+ DNS.2 = ecouser.net
+ DNS.3 = *.ecouser.net
+ DNS.4 = ecovacs.net
+ DNS.5 = *.ecovacs.net
+ ````
+
+1. Create certconfig.txt for use in later commands
+ certconfig.txt
+ ````
+ [ req ]
+ default_md = sha256
+ prompt = no
+ req_extensions = req_ext
+ distinguished_name = req_distinguished_name
+ [ req_distinguished_name ]
+ commonName = Bumper Server
+ organizationName = Bumper
+ [ req_ext ]
+ subjectKeyIdentifier = hash
+ authorityKeyIdentifier = keyid:always,issuer
+ keyUsage=critical,digitalSignature,keyEncipherment
+ extendedKeyUsage=serverAuth,clientAuth
+ basicConstraints=critical,CA:false
+ subjectAltName = @alt_names
+ [ alt_names ]
+ DNS.0 = ecovacs.com
+ DNS.1 = *.ecovacs.com
+ DNS.2 = ecouser.net
+ DNS.3 = *.ecouser.net
+ DNS.4 = ecovacs.net
+ DNS.5 = *.ecovacs.net
+ ````
+
+1. Generate the RSA private key
+`openssl genpkey -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out priv.key`
+
+1. Create the CSR
+`openssl req -new -nodes -key priv.key -config csrconfig.txt -out cert.csr`
+
+1. Sign your CSR with a root CA cert
+`openssl x509 -req -in cert.csr -days 3650 -CA ca.crt -CAkey priv.key -extfile certconfig.txt -extensions req_ext -CAserial /tmp/tmp-10593TSH1OlVSxC7C -CAcreateserial -out cert.crt`
+
+## Using a Custom CA/Self
+
+This should work siimilar to the OpenSSL method. Ensure the server certificate has the proper [SANs](#subject-alternative-name) in place.
\ No newline at end of file
diff --git a/docs/DNS_Setup.md b/docs/DNS_Setup.md
index 65e4a42..e90d378 100644
--- a/docs/DNS_Setup.md
+++ b/docs/DNS_Setup.md
@@ -28,13 +28,23 @@ Not all domains have been documented at this point, and this list will be update
- Example: If you see `eco-{countrycode}-api.ecovacs.com` and you live in the US/North America you would use: `eco-us-api.ecovacs.com`
-| Address | Description |
-|--|--|
-| `lb-{countrycode}.ecovacs.net` | Load-balancer that is checked by the app/robot |
-| `eco-{countrycode}-api.ecovacs.com` | Used for Login |
-| `portal-{countrycode}.ecouser.net` | Used for Login and Rest API |
-| `portal-ww.ecouser.net` | Used for various Rest APIs |
-| `msg-{countrycode}.ecouser.net` | Used for XMPP |
-| `mq-ww.ecouser.net` | Used for MQTT |
-| `gl-{countrycode}-api.ecovacs.com` | Used by Ecovacs Home app for API |
-| `recommender.ecovacs.com` | Used by Ecovacs Home app |
\ No newline at end of file
+| Address | Description |
+| --------------------------------------- | ---------------------------------------------- |
+| `lb-{countrycode}.ecovacs.net` | Load-balancer that is checked by the app/robot |
+| `lb-{countrycode}.ecouser.net` | Load-balancer that is checked by the app/robot |
+| `lbus.ecouser.net` | Load-balancer that is checked by the app/robot |
+| `lb{countrycode}.ecouser.net` | Load-balancer that is checked by the app/robot |
+| `eco-{countrycode}-api.ecovacs.com` | Used for Login |
+| `gl-{countrycode}-api.ecovacs.com` | Used by EcoVacs Home app |
+| `gl-{countrycode}-openapi.ecovacs.com` | Used by EcoVacs Home app |
+| `portal-{countrycode}.ecouser.net` | Used for Login and Rest API |
+| `portal-ww.ecouser.net` | Used for various Rest APIs |
+| `msg-{countrycode}.ecouser.net` | Used for XMPP |
+| `msg-ww.ecouser.net` | Used for XMPP |
+| `mq-ww.ecouser.net` | Used for MQTT |
+| `mq-{countrycode}.ecouser.net` | Used for MQTT |
+| `gl-{countrycode}-api.ecovacs.com` | Used by Ecovacs Home app for API |
+| `recommender.ecovacs.com` | Used by Ecovacs Home app |
+| `bigdata-international.ecovacs.com` | Telemetry/tracking |
+| `bigdata-northamerica.ecovacs.com` | Telemetry/tracking |
+| `bigdata-{unknown regions}.ecovacs.com` | Telemetry/tracking |
diff --git a/docs/Env_Var.md b/docs/Env_Var.md
new file mode 100644
index 0000000..f5b0697
--- /dev/null
+++ b/docs/Env_Var.md
@@ -0,0 +1,14 @@
+# Environment Variables
+
+Bumper has a number of environment variables to help with custom deployments and configuration. These should be set prior to executing Bumper.
+
+| Setting | Value | Description |
+| ------------------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
+| BUMPER_LISTEN | {ipv4 address} | IP address to start server listeners on |
+| BUMPER_ANNOUNCE_IP | {ipv4 address} | IP address to tell bots when they request the server location. May need to be set in cases such as when LISTEN is 0.0.0.0. |
+| BUMPER_CA | {full path to ca.crt location} | The public CA certificate (ca.crt) to be loaded |
+| BUMPER_CERT | {full path to bumper.crt location} | The public server certificate (bumper.crt) to be used by the Bumper server |
+| BUMPER_KEY | {full path to bumper.key location} | The private server key (bumper.key) to be used by the Bumper server |
+| BUMPER_LOGS | {full path to logs directory} | The directory where logs should be stored |
+| BUMPER_DATA | {full path to data directory} | The directory where persistent data should be stored (bumper.db) |
+| BUMPER_DEBUG | true | Run Bumper with debug mode/logging |
\ No newline at end of file
diff --git a/docs/How_It_Works.md b/docs/How_It_Works.md
index ed8eec1..978b46b 100644
--- a/docs/How_It_Works.md
+++ b/docs/How_It_Works.md
@@ -4,11 +4,11 @@ Bumper runs multiple services to re-create what the central EcoVacs servers prov
**Services**
-| Service | Description | Ports | Source File |
-|--|--|--|--|
+| Service | Description | Ports | Source File |
+| ----------- | ------------------------------------------------ | ------------ | --------------- |
| Web Servers | Provide authentication and for MQTT bots command | 443 and 8007 | `confserver.py` |
-| XMPP Server | For bots that utilize this protocol | 5223 | `xmppserver.py` |
-| MQTT Server | For bots that utilize this protocol | 8883 | `mqttserver.py` |
+| XMPP Server | For bots that utilize this protocol | 5223 | `xmppserver.py` |
+| MQTT Server | For bots that utilize this protocol | 8883 | `mqttserver.py` |
**App/Authentication**
diff --git a/logs/README.md b/logs/README.md
new file mode 100644
index 0000000..7e8687a
--- /dev/null
+++ b/logs/README.md
@@ -0,0 +1,3 @@
+# Logs Directory
+
+When Bumper executes, logs will be created here
diff --git a/start_bumper.py b/start_bumper.py
deleted file mode 100644
index 677e219..0000000
--- a/start_bumper.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-
-import logging
-import bumper
-import sys, socket
-import time
-import platform
-import os
-
-# os.environ['PYTHONASYNCIODEBUG'] = '1' # Uncomment to enable ASYNCIODEBUG
-import asyncio
-
-
-async def main():
- try:
- loop = asyncio.get_event_loop()
- except:
- loop = asyncio.new_event_loop()
-
- args = sys.argv
- listen_host = ""
-
- if len(args) > 0:
- if "--debug" in args:
- logging.basicConfig(
- level=logging.DEBUG,
- format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(module)s :: %(funcName)s :: %(lineno)d :: %(message)s",
- )
- loop.set_debug(True) # Set asyncio loop to debug
- # logging.getLogger("asyncio").setLevel(logging.DEBUG) # Show debug asyncio logs (disabled in init, uncomment for debugging asyncio)
- else:
- logging.basicConfig(
- level=logging.INFO,
- format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s",
- )
-
- if "--listen" in args:
- listen_host = args[args.index("--listen") + 1]
-
- if listen_host == "":
- if platform.system() == "Darwin": # If a Mac, use 0.0.0.0 for listening
- listen_host = "0.0.0.0"
- else:
- listen_host = socket.gethostbyname(socket.gethostname())
-
- conf_address_443 = (listen_host, 443)
- conf_address_8007 = (listen_host, 8007)
- xmpp_address = (listen_host, 5223)
- mqtt_address = (listen_host, 8883)
-
- mqtt_server = bumper.MQTTServer(mqtt_address)
- mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
- conf_server = bumper.ConfServer(
- conf_address_443, usessl=True, helperbot=mqtt_helperbot
- )
- conf_server_2 = bumper.ConfServer(
- conf_address_8007, usessl=False, helperbot=mqtt_helperbot
- )
- xmpp_server = bumper.XMPPServer(xmpp_address)
-
- try:
- # Start web servers
- conf_server.confserver_app()
- asyncio.create_task(conf_server.start_server())
-
- conf_server_2.confserver_app()
- asyncio.create_task(conf_server_2.start_server())
-
- # Start MQTT Server
- asyncio.create_task(mqtt_server.broker_coro())
-
- # Start MQTT Helperbot
- asyncio.create_task(mqtt_helperbot.start_helper_bot())
-
- # Start XMPP Server
- asyncio.create_task(xmpp_server.start_async_server())
-
- maintain = asyncio.create_task(maintenance_tasks())
- await maintain # Keeps the loop running until this exits
-
- finally:
- # Cleanup and close tasks/loop
- for task in asyncio.Task.all_tasks():
- task.cancel()
- loop.close()
-
-
-async def maintenance_tasks():
- while True:
- await asyncio.sleep(30) # Sleep 30 seconds
- bumper.revoke_expired_tokens()
-
-
-if __name__ == "__main__":
- try:
- asyncio.run(main())
-
- except KeyboardInterrupt:
- bumper.bumperlog.info("Keyboard Interrupt!")
- pass
- finally:
- bumper.bumperlog.info("Bumper Exiting!")
diff --git a/tests/pytest.ini b/tests/pytest.ini
new file mode 100644
index 0000000..9ca2dc7
--- /dev/null
+++ b/tests/pytest.ini
@@ -0,0 +1,5 @@
+[pytest]
+env =
+ D:BUMPER_CA=tests/test_certs/ca.crt
+ D:BUMPER_CERT=tests/test_certs/bumper.crt
+ D:BUMPER_KEY=tests/test_certs/bumper.key
diff --git a/tests/test_certs/bumper.crt b/tests/test_certs/bumper.crt
new file mode 100644
index 0000000..c80e131
--- /dev/null
+++ b/tests/test_certs/bumper.crt
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgICBnowDQYJKoZIhvcNAQELBQAwJTEPMA0GA1UEChMGQnVt
+cGVyMRIwEAYDVQQDEwlCdW1wZXIgQ0EwHhcNMTkwNjA2MTMwMTE3WhcNMjkwNjA2
+MTMwMTE3WjApMQ8wDQYDVQQKEwZCdW1wZXIxFjAUBgNVBAMTDUJ1bXBlciBTZXJ2
+ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDN94pW5U+IJ70BQRKO
+5Va2Inuef9AMvTm11pZMStvIskuzCi+fiIXhrPyKXRNbg21MX9eTrbEfc8t1sBKU
+3rYdZ+JteE+9f4pJjHXEyJSMiPZcmGKC3CbSZyuPgw9asLch6FENrwDcxEV7HbJd
+oINOjwVqXXPdsSRk2GPuvHjvlwC0h0vt/fErQhlD8U3TIIRDtCfg0BSQUuLXBfJh
+R1aksl2nwWQTu62akWTxlZ7hQnkk1WldjIqQarjyaY7Uh0L0/kRpnbhmnW085gzc
+E2bi0YwZ7WPwAwPvEszJr30piPtt71JzPPvPUdIcsTj2HotWyAT1ljdxfaKvWgI3
+HemrAgMBAAGjggGQMIIBjDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
+BQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMiQCLdfA6g8
+0xTW2wROUJ42R06hMB8GA1UdIwQYMBaAFKYPByFyuubjTQKzczNsX045VPDbMIIB
+CwYDVR0RBIIBAjCB/4ILZWNvdmFjcy5jb22CDSouZWNvdmFjcy5jb22CC2Vjb3Vz
+ZXIubmV0gg0qLmVjb3VzZXIubmV0ggtlY292YWNzLm5ldIINKi5lY292YWNzLm5l
+dIIIbWFjYm9vazGCCWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAAYcQ
+/oAAAAAAAAAAAAAAAAAAAYcQ/oAAAAAAAAAE2n0e5bOcu4cECgABKIcQ/oAAAAAA
+AABAPHz//ktLWIcQ/oAAAAAAAAD+dglg8MXdSIcQ/oAAAAAAAAALkYrhchk/YIcQ
+/oAAAAAAAAAY1ZBa52Ist4cECgABCocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA
+QSFKoR3LxCk0N1eaNm44WF7ho57l1XhqQKWojljsJYWoc+LwcWamdyfTJ5M1o07/
+yIMh16VRFnjr1NPTk9WmLCcy5VN0oP24XAF9VeX5Q2Rkj8j3e7RmRn5jn0BH6sxk
+X/a9GMuEqSDYi6j9ggi9AEdAM8tyfcEkXEP3pdVW29je8F0u7Hia42zGUjGwjndl
+2Q8mYBKr0ViG1UV7bKAEJl/WvnOTxpp8ZSTLr6RSleGZ7JvCGpISPzNgeIuPRKOT
+D77LiGnDdKgJnuwx266tuKV5AN4B3okG/AqbmFtB/LFfNE2769g94pG6jpVZpSum
+kq2jok6bnc1fdGkO0ou15w==
+-----END CERTIFICATE-----
diff --git a/tests/test_certs/bumper.key b/tests/test_certs/bumper.key
new file mode 100644
index 0000000..9dfc1df
--- /dev/null
+++ b/tests/test_certs/bumper.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAzfeKVuVPiCe9AUESjuVWtiJ7nn/QDL05tdaWTErbyLJLswov
+n4iF4az8il0TW4NtTF/Xk62xH3PLdbASlN62HWfibXhPvX+KSYx1xMiUjIj2XJhi
+gtwm0mcrj4MPWrC3IehRDa8A3MRFex2yXaCDTo8Fal1z3bEkZNhj7rx475cAtIdL
+7f3xK0IZQ/FN0yCEQ7Qn4NAUkFLi1wXyYUdWpLJdp8FkE7utmpFk8ZWe4UJ5JNVp
+XYyKkGq48mmO1IdC9P5EaZ24Zp1tPOYM3BNm4tGMGe1j8AMD7xLMya99KYj7be9S
+czz7z1HSHLE49h6LVsgE9ZY3cX2ir1oCNx3pqwIDAQABAoIBADpMVLXf1jEdvlu6
+hXw44eBPxlnIp6TTcqBLiuMxVSBrhw24Vl57kBmekyS+z5nZi3hQsH42baoPZol7
+Ouc0WqvcGbUOltN2ZDgJL9RxScq1gbYX09piYgKv/R5z5EaxOkS4syiCXmYej+QX
+NcNWiZQU212N8hvP5hM9RJvwcPKvcpQIrW5NdcMvhok+kd/abJcIzXhLXEyLcrRJ
+XZh6cCesUZQnZWPVecM+bc/Wt9U5pbw/PNTTiQSFW6wrjCOXVKA57p/zmeb3EWFd
+V/rlho+QXLBo9I0DLZKScCfMHgVoguK5Ud7drGiB5rPlgPAv0sFW7fhUd1j7hX7H
+l4uDrqECgYEA+6xJgJzJp//6eR3wNiSp/4Y8vY+WCtWNCOwhJbw1a8co5Sex0vAk
+0y3mye+4rOgRbfXhhpPm+y+EnHbXlVk8Ux37OfxHviewCiRbkjRU3uycE60ZFtLr
+rdqA9FNwutfz3AJqJ/zjVoMneeO7h/GkIAHqxOJHAACV/+lObrSMO0MCgYEA0YIV
+M032bk+q9zgfd0IY1ZdUhUS2QyQhMY380F+Dym69Xv2FmG+zeynJT5jxrZs3kmcN
+X9jnscTIMGO70EHq2sI/h9IFfqr/7iTlbwgpYeKEPYqWkmuetiKziVOL/Uf4USPd
+bQiWRIaQpSZFXUCjVrKL8nGdxhA73iOuQKLmjXkCgYEA2mHxlex2/5Sbn6Ve31yJ
+NvUgl8yUgeo0a12alcfvAwrabZ44K7W9/pGCBhBBy6fEGAqYG9MTRztAcxSclTfN
+pMILUZGcH2EI3IQYAZHvY1ElTd2SO7/iSgWkiF4vH7JsJKjjvLcv/c3o31fBToFb
+zXpcYWOIAHSBtIKaUG3SkUkCgYBiJq4l9f1gWqR+42Uiau3ViusG8FTvCYsfeySY
+vlawzMadLOqcqqAMMFxmlQGMUq5rQSor4CNTzhv3R5Iik+8iA2TeDY+Tcyspd1Gh
+fdJdUFChwD6gZBjbvVAdIu3vf/sekE3ZGe/ENMKpDE/syy56nHUh5QaEVvClNlQZ
+ZffbCQKBgHM2fk3Nlsjk7UCVb8P2hZdX4gx83OJDJPfIfpu/Sf5vPDpmeADI0L30
+wlMLo+px1bYBqP6sNx0E1iaBces+WqALnR1tIypItVJmZF7eGeWmJ/KJX1FwtYec
+D0cElOusX7pIo6s3lTw4KMxPOMPYRt75zlboVEi+z4cNOCXjf49B
+-----END RSA PRIVATE KEY-----
diff --git a/tests/test_certs/ca.crt b/tests/test_certs/ca.crt
new file mode 100644
index 0000000..b346818
--- /dev/null
+++ b/tests/test_certs/ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKTCCAhGgAwIBAgICBnUwDQYJKoZIhvcNAQELBQAwJTEPMA0GA1UEChMGQnVt
+cGVyMRIwEAYDVQQDEwlCdW1wZXIgQ0EwHhcNMTkwNjA2MTMwMTE3WhcNMjkwNjA2
+MTMwMTE3WjAlMQ8wDQYDVQQKEwZCdW1wZXIxEjAQBgNVBAMTCUJ1bXBlciBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPOE/zW15yRS7jZhlF0K1s8c
+8tN5tYWVieeGCbmdk89vtTA/doYbvbP0ut95OUSS8YEDP98UdqzoTXpYqNehnk5q
+VjRyHyXxv2KekhxmTmv+f5OXns8fCgoNlOWAugAlXgk+LGy7non+RLNQ5/vh8E/C
+IE0lbxelptkOMirboFPP4LIFqHMjERlC6m63LBftVjRCjDzoWtN9XNCquan27fBd
+5/I3wdEBdDcGA7heGPXKrkzyaiZUncHQD3oqbn05ScUFvSJAs7bz4Qdslkna7zK1
+AAJoXEBAjWTTau8xp4Fp1qzloMMh0RrqCBgeBlGeL6OcqvMUNRrFNnuDxEXXuTsC
+AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFKYPByFyuubjTQKzczNsX045VPDbMB8GA1UdIwQYMBaAFKYPByFyuubjTQKz
+czNsX045VPDbMA0GCSqGSIb3DQEBCwUAA4IBAQCy0dzBuANBlmL58XtvwvrSxhJr
+oBscfqeYRvWaUkSAbVX4aH7UsUQWDiLtJZdLsWxMLl0LqbDo+t3I8kpSxOAkJ+Dn
+zkLAL2ze0ivZEYkLqGXhO+lEK8YcFWJxkgIA/aykmI7suQyv/1x67mTpCVbxMjbI
+iVv11L2o9Ilu/ZLIlRg5G3vnTz7Eql3JMFUN+hHzEzuNTyl9JkSUIZJLQyqg3u4Y
+NIGD3nxFiNM1LL17Baz2EjfloAoSyaPGZUzKyRT2BUzHCs2vBNnbTN+XRBHJGZX/
+VU76YW8l/f6OPzP6XR3noI6Rpm5OpTOrQTTqmYkcb3QwhBD3I4Aqyjs/qxIT
+-----END CERTIFICATE-----
diff --git a/tests/test_certs/ca.key b/tests/test_certs/ca.key
new file mode 100644
index 0000000..cd7f03a
--- /dev/null
+++ b/tests/test_certs/ca.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA84T/NbXnJFLuNmGUXQrWzxzy03m1hZWJ54YJuZ2Tz2+1MD92
+hhu9s/S633k5RJLxgQM/3xR2rOhNelio16GeTmpWNHIfJfG/Yp6SHGZOa/5/k5ee
+zx8KCg2U5YC6ACVeCT4sbLueif5Es1Dn++HwT8IgTSVvF6Wm2Q4yKtugU8/gsgWo
+cyMRGULqbrcsF+1WNEKMPOha031c0Kq5qfbt8F3n8jfB0QF0NwYDuF4Y9cquTPJq
+JlSdwdAPeipufTlJxQW9IkCztvPhB2yWSdrvMrUAAmhcQECNZNNq7zGngWnWrOWg
+wyHRGuoIGB4GUZ4vo5yq8xQ1GsU2e4PERde5OwIDAQABAoIBAQCUveGcjvUWDMmP
+0d5rTlmSvB3d6fNkGsjW79o00/katSK4y6q7k2o15v/VzBecuRxmLvPucHNkfagF
+WO4Yd5FYWD87XZGE/bpmpHCehCbWc+a84dmQrWbWaSFPZWc2+5wKjT1ZVOgrZXHV
+DVAFXCYKsYpFVN4cVYQqBC/EWc3+IkQXcw8POLNwa0ml6ZyFZOcmpik/5o+EbCH2
+KL+Rqqi1iKnMKdR9HG9yg7PCk140/Zn0Z5ROWpGehFy1xNlh/+DO9Fjbkm+Zj3sU
+/X3UfRRe1Gtbt8z68fZxLqjJfBMujc+J5kSVMn0MH3vXfCLTSktGaxZmHC5xhk36
+59QzpQ7hAoGBAPdvFoaD9jJ8bF3nwIJ2uxYAhH/y9IYb4rW4FN1Dz/fBJuIZ8JO9
+NBDHX1JK1NzgjTE0mqZ0C5UQTNR9FMBVe0iTFDpndL6YcOtU0LIyHeePNGqnVWMp
+SjjrjtjSO0Uug7YKSuLOrfMtKZyN0t19KDllThoMZlxSoiTL1Jzor0BJAoGBAPvz
+N4kp8t+ngCl/BoHVEKjhtYe90m0VQflwVfl+myJwIVjtEJliAn2ZZ4uKeTqY1EGE
+cAKwikpxI3yDVetM/hrivOEcULbk1SwhcmtTaaGCAw6iLm32suPcEROnSQF/FVyj
+BxyvHyrSG7FRh6f4YcMg3G6W7VxE4IYVgoVdLPVjAoGBAKBOnK1x+aQj8KG2cIcW
+HYfXtgCfi8UHdA5/wSTJtoex4FtEqxVM09q7EQrj6J1h7pgemMOXE5n0AZL5puQl
+fcY7ZDOiq4SAh0gwnzWUOsO3iCJBX5TrP2c5VkcrjbL4u+TJLlNbzF9stzTyvdc6
+K0FkXQGLXxYZg2uLk6hFKKXhAoGAODCN+jE40Vhx5M9HjD0QchmkepmDDIDpLdA3
+3GS4BH4tcb+tLAgHtis4RI6lasQa0mHO+UqWDPQeje5cgxWwth5LMYk3FxMB1829
+zuHTdQmh1OmmoS+bxeWWiWONjJ/jC73wIB2OPeaN9oXQU025v+LcRm2ykhlqWX0C
+luuo0zECgYEA6FI0/2L+3prIQ6ravX2sWNMEFeWMEUg/ld8lHcOZ+amAuLzMvrPO
+oSVb3JQ+OQbpVsorNBjWqQwbUKTJ3zU9/ievyptCs3G39aQ2wUsDdYKfpkxnfKFe
+ZgU5YfwB54rgkQc4vCheTnWo/JuhyB5cgvtjtKOdtMKhXfwpX0bFA/w=
+-----END RSA PRIVATE KEY-----
diff --git a/tests/test_confserver.py b/tests/test_confserver.py
index 3c85115..15fdac7 100644
--- a/tests/test_confserver.py
+++ b/tests/test_confserver.py
@@ -26,6 +26,11 @@ def async_return(result):
return f
+def remove_existing_db():
+ if os.path.exists("tests/tmp.db"):
+ os.remove("tests/tmp.db") # Remove existing db
+
+
async def test_confserver_ssl():
conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=True, helperbot=None)
conf_server.confserver_app()
@@ -39,8 +44,7 @@ async def test_confserver_no_ssl():
async def test_base(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -51,8 +55,7 @@ async def test_base(aiohttp_client):
async def test_login(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -66,8 +69,7 @@ async def test_login(aiohttp_client):
assert "uid" in jsonresp["data"]
assert "username" in jsonresp["data"]
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
# Test global_e without user
@@ -104,8 +106,7 @@ async def test_login(aiohttp_client):
async def test_logout(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -126,8 +127,7 @@ async def test_logout(aiohttp_client):
async def test_checkLogin(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -217,8 +217,7 @@ async def test_checkLogin(aiohttp_client):
async def test_getAuthCode(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -273,8 +272,7 @@ async def test_getAuthCode(aiohttp_client):
async def test_checkAgreement(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -295,8 +293,7 @@ async def test_checkAgreement(aiohttp_client):
async def test_homePageAlert(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -310,8 +307,7 @@ async def test_homePageAlert(aiohttp_client):
async def test_checkVersion(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -323,8 +319,7 @@ async def test_checkVersion(aiohttp_client):
async def test_checkAppVersion(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -338,8 +333,7 @@ async def test_checkAppVersion(aiohttp_client):
async def test_uploadDeviceInfo(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -353,8 +347,7 @@ async def test_uploadDeviceInfo(aiohttp_client):
async def test_getAdByPositionType(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -368,8 +361,7 @@ async def test_getAdByPositionType(aiohttp_client):
async def test_getBootScreen(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -383,8 +375,7 @@ async def test_getBootScreen(aiohttp_client):
async def test_hasUnreadMsg(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -398,8 +389,7 @@ async def test_hasUnreadMsg(aiohttp_client):
async def test_getMsgList(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -413,8 +403,7 @@ async def test_getMsgList(aiohttp_client):
async def test_getSystemReminder(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -428,8 +417,7 @@ async def test_getSystemReminder(aiohttp_client):
async def test_getCnWapShopConfig(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -443,8 +431,7 @@ async def test_getCnWapShopConfig(aiohttp_client):
async def test_neng_hasUnreadMessage(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -466,8 +453,7 @@ async def test_neng_hasUnreadMessage(aiohttp_client):
async def test_getProductIotMap(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -479,8 +465,7 @@ async def test_getProductIotMap(aiohttp_client):
async def test_getUsersAPI(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -492,8 +477,7 @@ async def test_getUsersAPI(aiohttp_client):
async def test_getUserAccountInfo(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.user_add("testuser")
bumper.user_add_device("testuser", "dev_1234")
@@ -516,8 +500,7 @@ async def test_getUserAccountInfo(aiohttp_client):
async def test_postUsersAPI(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -668,8 +651,7 @@ async def test_postUsersAPI(aiohttp_client):
async def test_appsvr_api(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -708,8 +690,7 @@ async def test_appsvr_api(aiohttp_client):
async def test_lg_logs(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.bot_add("sn_1234", "did_1234", "ls1ok3", "res_1234", "eco-ng")
bumper.bot_set_mqtt("did_1234", True)
@@ -725,7 +706,6 @@ async def test_lg_logs(aiohttp_client):
confserver.helperbot.send_command = mock.MagicMock(
return_value=async_return(command_getstatus_resp)
)
-
# Test GetGlobalDeviceList
postbody = {
@@ -756,8 +736,7 @@ async def test_lg_logs(aiohttp_client):
async def test_postLookup(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
client = await aiohttp_client(create_app)
@@ -779,8 +758,7 @@ async def test_postLookup(aiohttp_client):
async def test_devmgr(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
confserver = create_confserver()
client = await aiohttp_client(create_app)
@@ -800,7 +778,7 @@ async def test_devmgr(aiohttp_client):
text = await resp.text()
test_resp = json.loads(text)
assert test_resp["ret"] == "ok"
- assert test_resp["unRead"] == False
+ assert test_resp["unRead"] == False
# Test BotCommand
bumper.bot_add("sn_1234", "did_1234", "dev_1234", "res_1234", "eco-ng")
@@ -846,8 +824,7 @@ async def test_devmgr(aiohttp_client):
async def test_dim_devmanager(aiohttp_client):
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
+ remove_existing_db()
bumper.db = "tests/tmp.db" # Set db location for testing
confserver = create_confserver()
client = await aiohttp_client(create_app)
diff --git a/tests/test_init.py b/tests/test_init.py
index d1e9060..88faec4 100644
--- a/tests/test_init.py
+++ b/tests/test_init.py
@@ -1,4 +1,5 @@
import mock
+from mock import patch
import pytest
from tinydb.storages import MemoryStorage
from tinydb import TinyDB, Query
@@ -6,6 +7,9 @@ import bumper
import os
import datetime, time
import platform
+import json
+import asyncio
+from testfixtures import LogCapture
def test_get_milli_time():
@@ -19,23 +23,61 @@ def test_get_milli_time():
)
+def test_strtobool():
+ assert bumper.strtobool("t") == True
+ assert bumper.strtobool("f") == False
+ assert bumper.strtobool(0) == False
+
+async def test_start_stop():
+ with LogCapture() as l:
+ if os.path.exists("tests/tmp.db"):
+ os.remove("tests/tmp.db") # Remove existing db
+
+ b = bumper
+ b.db = "tests/tmp.db" # Set db location for testing
+ b.conf1_listen_address = "0.0.0.0"
+ b.conf1_listen_port = 443
+ asyncio.create_task(b.start())
+ await asyncio.sleep(0.1)
+ l.check_present(("bumper", "INFO", "Starting Bumper"))
+ l.clear()
+ assert b.shutting_down == False
+ asyncio.create_task(b.shutdown())
+ await asyncio.sleep(0.1)
+ l.check_present(
+ ("bumper", "INFO", "Shutting down"), ("bumper", "INFO", "Shutdown complete")
+ )
+ assert b.shutting_down == True
+
+
+async def test_start_stop_debug():
+ with LogCapture() as l:
+ if os.path.exists("tests/tmp.db"):
+ os.remove("tests/tmp.db") # Remove existing db
+
+ b = bumper
+ b.db = "tests/tmp.db" # Set db location for testing
+ b.bumper_listen = "0.0.0.0"
+ b.bumper_debug = True
+ asyncio.create_task(b.start())
+
+ await asyncio.sleep(0.1)
+ asyncio.create_task(b.shutdown())
+ l.check_present(("bumper", "INFO", "Starting Bumper"))
+ l.clear()
+ await asyncio.sleep(0.1)
+ l.check_present(
+ ("bumper", "INFO", "Shutting down"), ("bumper", "INFO", "Shutdown complete")
+ )
+ assert b.shutting_down == True
+
+
+def test_db_path():
+ bumper.db = None
+ assert bumper.db_file() == os.path.join(bumper.data_dir, "bumper.db")
+
+
def test_user_db():
- if os.path.exists("tests/tmp.db"):
- os.remove("tests/tmp.db") # Remove existing db
-
- # Test os_db_path
- platform.system = mock.MagicMock(return_value="Windows")
- p = platform.system()
- os.getenv = mock.MagicMock(return_value="C:\\AppData")
- o = os.getenv("APPDATA")
- assert bumper.os_db_path(createdir=False) == os.path.join(
- os.getenv("APPDATA"), "bumper.db"
- )
-
- platform.system = mock.MagicMock(return_value="Linux")
- assert bumper.os_db_path(createdir=False) == os.path.expanduser(
- "~/.config/bumper.db"
- )
bumper.db = "tests/tmp.db" # Set db location for testing
bumper.user_add("testuser") # Add testuser
diff --git a/tests/test_mqttserver.py b/tests/test_mqttserver.py
index 24ef16f..cf2232b 100644
--- a/tests/test_mqttserver.py
+++ b/tests/test_mqttserver.py
@@ -18,13 +18,6 @@ async def test_helperbot_message():
mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro()
- #broker = mqtt_server.broker
- #mqtt_address = ("127.0.0.1", 8883)
- #mqtt_server = bumper.MQTTServer(mqtt_address)
- #broker = hbmqtt.broker.Broker(
- # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins"
- #)
- #await broker.start()
# Test broadcast message
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
@@ -140,12 +133,12 @@ async def test_helperbot_expire_message():
mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro()
- #mqtt_address = ("127.0.0.1", 8883)
- #mqtt_server = bumper.MQTTServer(mqtt_address)
- #broker = hbmqtt.broker.Broker(
+ # mqtt_address = ("127.0.0.1", 8883)
+ # mqtt_server = bumper.MQTTServer(mqtt_address)
+ # broker = hbmqtt.broker.Broker(
# mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins"
- #)
- #await broker.start()
+ # )
+ # await broker.start()
# Test broadcast message
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
@@ -209,12 +202,12 @@ async def test_helperbot_sendcommand():
mqtt_address = ("127.0.0.1", 8883)
mqtt_server = bumper.MQTTServer(mqtt_address)
await mqtt_server.broker_coro()
- #mqtt_address = ("127.0.0.1", 8883)
- #mqtt_server = bumper.MQTTServer(mqtt_address)
- #broker = hbmqtt.broker.Broker(
+ # mqtt_address = ("127.0.0.1", 8883)
+ # mqtt_server = bumper.MQTTServer(mqtt_address)
+ # broker = hbmqtt.broker.Broker(
# mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins"
- #)
- #await broker.start()
+ # )
+ # await broker.start()
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
await mqtt_helperbot.start_helper_bot()
@@ -334,7 +327,7 @@ async def test_mqttserver():
mqtt_helperbot.Client._connected_state._value == True
) # Check helperbot is connected
await mqtt_helperbot.Client.disconnect()
-
+
# Test client connect
bumper.user_add("user_123") # Add user to db
bumper.client_add("user_123", "ecouser.net", "resource_123") # Add client to db
@@ -365,7 +358,7 @@ async def test_mqttserver():
fake_bot.Client._connected_state._value == True
) # Check fake_bot is connected
await fake_bot.Client.disconnect()
-
+
await asyncio.sleep(0.1)
- await mqtt_server.broker.shutdown()
\ No newline at end of file
+ await mqtt_server.broker.shutdown()
diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py
index 6ed558a..74d2a0c 100644
--- a/tests/test_xmppserver.py
+++ b/tests/test_xmppserver.py
@@ -221,16 +221,12 @@ async def test_xmpp_server_client_tls():
await writer.drain()
- await asyncio.sleep(0.1)
-
writer.write(
b'AGZ1aWRfdG1wdXNlcgAwL0lPU0Y1M0QwN0JBL3VzXzg5ODgwMmZkYmM0NDQxYjBiYzgxNWIxZDFjNjgzMDJl'
) # Send Auth
await writer.drain()
- await asyncio.sleep(0.1)
-
xmpp_address = ("127.0.0.1", 5223)
xmpp_server = bumper.XMPPServer(xmpp_address)
await xmpp_server.start_async_server()
diff --git a/tests/test_z_problem.py b/tests/test_z_problem.py
new file mode 100644
index 0000000..bf93b00
--- /dev/null
+++ b/tests/test_z_problem.py
@@ -0,0 +1,111 @@
+import mock
+from mock import patch
+import pytest
+from tinydb.storages import MemoryStorage
+from tinydb import TinyDB, Query
+import bumper
+import os
+import datetime, time
+import platform
+import json
+import asyncio
+from testfixtures import LogCapture
+import sys
+
+
+@patch("bumper.firstrun_input")
+@patch("bumper.create_certs")
+def test_firstrun(mock_input, mock_create):
+ with LogCapture() as l:
+
+ bumper.firstrun_input.return_value = "n"
+ bumper.first_run()
+ l.check_present(
+ (
+ "root",
+ "CRITICAL",
+ "Can't continue without certificates, please create some then try again.",
+ )
+ )
+
+ bumper.firstrun_input.return_value = "y"
+ bumper.first_run()
+ assert mock_create.called == True
+
+
+def mock_subrun(*args):
+ return args
+
+@patch("bumper.start")
+def test_argparse(mock_start):
+ bumper.ca_cert = "tests/test_certs/ca.crt"
+ bumper.server_cert = "tests/test_certs/bumper.crt"
+ bumper.server_key = "tests/test_certs/bumper.key"
+
+ bumper.main(["--debug"])
+ assert bumper.bumper_debug == True
+ assert mock_start.called == True
+
+ bumper.main(["--listen", "127.0.0.1"])
+ assert bumper.bumper_listen == "127.0.0.1"
+ assert mock_start.called == True
+
+ bumper.main(["--announce", "127.0.0.1"])
+ assert bumper.bumper_announce_ip == "127.0.0.1"
+ assert mock_start.called == True
+
+ bumper.main(["--debug", "--listen", "127.0.0.1", "--announce", "127.0.0.1"])
+ assert bumper.bumper_debug == True
+ assert bumper.bumper_announce_ip == "127.0.0.1"
+ assert bumper.bumper_listen == "127.0.0.1"
+ assert mock_start.called == True
+
+
+@patch("subprocess.run")
+@patch("platform.system")
+@patch("platform.machine")
+@patch("os.execv")
+def test_createcert(mock_run, mock_platform, mock_machine, mock_exec):
+ mock_run.side_effect = mock_subrun
+ platform.system.return_value = "darwin"
+ bumper.create_certs()
+ assert mock_run.called == True
+ assert os.path.join("..", "create_certs", "create_certs_osx") in mock_exec.call_args.args[0]
+
+ platform.system.return_value = "windows"
+ bumper.create_certs()
+ assert mock_run.called == True
+ assert os.path.join("..", "create_certs", "create_certs_windows.exe") in mock_exec.call_args.args[0]
+
+ platform.system.return_value = "linux"
+ bumper.create_certs()
+ assert mock_run.called == True
+ assert os.path.join("..", "create_certs","create_certs_linux") in mock_exec.call_args.args[0]
+
+ platform.system.return_value = "linux"
+ platform.machine.return_value = "arm"
+ bumper.create_certs()
+ assert mock_run.called == True
+ assert os.path.join("..", "create_certs", "create_certs_rpi") in mock_exec.call_args.args[0]
+
+ with LogCapture() as l:
+ platform.system.return_value = "nixbad"
+ bumper.create_certs()
+
+ l.check_present(
+ (
+ "root",
+ "CRITICAL",
+ "Can't determine platform. Create certs manually and try again.",
+ )
+ )
+
+
+
+@patch("bumper.first_run")
+def test_main(mock_firstrun):
+ bumper.ca_cert = "sf"
+ bumper.main()
+ assert mock_firstrun.called == True
+ bumper.ca_cert = "tests/test_certs/ca.crt"
+
diff --git a/tests/tests.md b/tests/tests.md
index c485135..c4cbdaf 100644
--- a/tests/tests.md
+++ b/tests/tests.md
@@ -5,12 +5,12 @@ Bumper uses pytest for the majority of test cases. Install requirements using `
Enter pipenv shell `pipenv shell`
### Run tests
-`python -m pytest`
+`python -m pytest tests`
### Run tests with coverage
-`python -m pytest --cov=bumper tests/`
+`python -m pytest --cov=./ tests`
### Run tests with coverage html report
-`python -m pytest --cov=bumper tests/ --cov-report html:tests/report`
+`python -m pytest --cov=./ tests --cov-report html:tests/report`
The report will be output into tests/report/index.html for further analysis.
\ No newline at end of file