commit
edb6c7b5cc
54 changed files with 1219 additions and 1009 deletions
33
.gitignore
vendored
33
.gitignore
vendored
|
|
@ -1,10 +1,25 @@
|
|||
# Ignore pycache
|
||||
__pycache__
|
||||
.DS_Store
|
||||
.vscode/
|
||||
.coverage
|
||||
.noseids
|
||||
.pytest_cache
|
||||
nosetests.xml
|
||||
tests/report
|
||||
tests/tmp.db
|
||||
logs/
|
||||
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
2
Pipfile
2
Pipfile
|
|
@ -20,6 +20,8 @@ pytest-aiohttp = "*"
|
|||
pytest-cov = "*"
|
||||
testfixtures = "*"
|
||||
codecov = "*"
|
||||
autoflake = "*"
|
||||
pytest-env = "*"
|
||||
|
||||
[pipenv]
|
||||
allow_prereleases = true
|
||||
|
|
|
|||
47
Pipfile.lock
generated
47
Pipfile.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
48
README.md
48
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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
4
bumper/__main__.py
Normal file
4
bumper/__main__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import bumper
|
||||
|
||||
if __name__ == "__main__":
|
||||
bumper.main()
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>'
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
V 290129055932Z 99BD46167599BDB4 unknown /C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
|
||||
V 290129061718Z 99BD46167599BDB5 unknown /CN=Bumper
|
||||
|
|
@ -1 +0,0 @@
|
|||
unique_subject = yes
|
||||
|
|
@ -1 +0,0 @@
|
|||
unique_subject = yes
|
||||
|
|
@ -1 +0,0 @@
|
|||
V 290129055932Z 99BD46167599BDB4 unknown /C=US/ST=California/O=Bumper/OU=Bumper/CN=Bumper
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1 +0,0 @@
|
|||
99BD46167599BDB6
|
||||
|
|
@ -1 +0,0 @@
|
|||
99BD46167599BDB5
|
||||
3
certs/README.md
Normal file
3
certs/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Certs Directory
|
||||
|
||||
Place your created certs in this directory
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
6
create_certs/Bumper_SAN.txt
Normal file
6
create_certs/Bumper_SAN.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
ecovacs.com
|
||||
*.ecovacs.com
|
||||
ecouser.net
|
||||
*.ecouser.net
|
||||
ecovacs.net
|
||||
*.ecovacs.net
|
||||
BIN
create_certs/create_certs_linux
Executable file
BIN
create_certs/create_certs_linux
Executable file
Binary file not shown.
BIN
create_certs/create_certs_osx
Executable file
BIN
create_certs/create_certs_osx
Executable file
Binary file not shown.
BIN
create_certs/create_certs_rpi
Executable file
BIN
create_certs/create_certs_rpi
Executable file
Binary file not shown.
BIN
create_certs/create_certs_windows.exe
Executable file
BIN
create_certs/create_certs_windows.exe
Executable file
Binary file not shown.
12
create_certs/src/build.sh
Executable file
12
create_certs/src/build.sh
Executable file
|
|
@ -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"
|
||||
193
create_certs/src/create_certs.go
Normal file
193
create_certs/src/create_certs.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
3
data/README.md
Normal file
3
data/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Data Directory
|
||||
|
||||
Where Bumper executes persistent data will be stored here (bumper.db)
|
||||
163
docs/Create_Certs.md
Normal file
163
docs/Create_Certs.md
Normal file
|
|
@ -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.
|
||||
|
|
@ -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 |
|
||||
| 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 |
|
||||
|
|
|
|||
14
docs/Env_Var.md
Normal file
14
docs/Env_Var.md
Normal file
|
|
@ -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 |
|
||||
|
|
@ -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**
|
||||
|
||||
|
|
|
|||
3
logs/README.md
Normal file
3
logs/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Logs Directory
|
||||
|
||||
When Bumper executes, logs will be created here
|
||||
102
start_bumper.py
102
start_bumper.py
|
|
@ -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!")
|
||||
5
tests/pytest.ini
Normal file
5
tests/pytest.ini
Normal file
|
|
@ -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
|
||||
26
tests/test_certs/bumper.crt
Normal file
26
tests/test_certs/bumper.crt
Normal file
|
|
@ -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-----
|
||||
27
tests/test_certs/bumper.key
Normal file
27
tests/test_certs/bumper.key
Normal file
|
|
@ -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-----
|
||||
19
tests/test_certs/ca.crt
Normal file
19
tests/test_certs/ca.crt
Normal file
|
|
@ -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-----
|
||||
27
tests/test_certs/ca.key
Normal file
27
tests/test_certs/ca.key
Normal file
|
|
@ -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-----
|
||||
|
|
@ -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)
|
||||
|
|
@ -726,7 +707,6 @@ async def test_lg_logs(aiohttp_client):
|
|||
return_value=async_return(command_getstatus_resp)
|
||||
)
|
||||
|
||||
|
||||
# Test GetGlobalDeviceList
|
||||
postbody = {
|
||||
"auth": {
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -221,16 +221,12 @@ async def test_xmpp_server_client_tls():
|
|||
|
||||
await writer.drain()
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
writer.write(
|
||||
b'<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">AGZ1aWRfdG1wdXNlcgAwL0lPU0Y1M0QwN0JBL3VzXzg5ODgwMmZkYmM0NDQxYjBiYzgxNWIxZDFjNjgzMDJl</auth>'
|
||||
) # 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()
|
||||
|
|
|
|||
111
tests/test_z_problem.py
Normal file
111
tests/test_z_problem.py
Normal file
|
|
@ -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"
|
||||
|
||||
|
|
@ -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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue