- basic plugin system for confserver - allows adding api via plugins that can be saved in user data/plugins folder - relocated routes into internal plugins - add start_site to replace start_server - changed init code for starting confserver, this with the above fixes an issue of initializing the app twice
869 lines
No EOL
36 KiB
Python
869 lines
No EOL
36 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
import logging
|
|
import ssl
|
|
import string
|
|
import random
|
|
import bumper
|
|
import os
|
|
from bumper.models import *
|
|
from bumper import plugins
|
|
from datetime import datetime, timedelta
|
|
import asyncio
|
|
from aiohttp import web
|
|
import aiohttp_jinja2
|
|
import jinja2
|
|
import uuid
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
class aiohttp_filter(logging.Filter):
|
|
def filter(self, record):
|
|
if (
|
|
record.name == "aiohttp.access" and record.levelno == 20
|
|
): # Filters aiohttp.access log to switch it from INFO to DEBUG
|
|
record.levelno = 10
|
|
record.levelname = "DEBUG"
|
|
|
|
if (
|
|
record.levelno == 10
|
|
and logging.getLogger("confserver").getEffectiveLevel() == 10
|
|
):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
confserverlog = logging.getLogger("confserver")
|
|
logging.getLogger("aiohttp.access").addFilter(
|
|
aiohttp_filter()
|
|
) # Add logging filter above to aiohttp.access
|
|
|
|
|
|
class ConfServer:
|
|
def __init__(self, address, usessl=False):
|
|
self.usessl = usessl
|
|
self.address = address
|
|
self.app = None
|
|
self.site = None
|
|
self.runner = None
|
|
self.runners = []
|
|
self.excludelogging = ["base", "remove-bot", "remove-client", "restart-service"]
|
|
|
|
def get_milli_time(self, timetoconvert):
|
|
return int(round(timetoconvert * 1000))
|
|
|
|
def confserver_app(self):
|
|
self.app = web.Application(loop=asyncio.get_event_loop(), middlewares=[
|
|
self.log_all_requests,
|
|
])
|
|
aiohttp_jinja2.setup(self.app, loader=jinja2.FileSystemLoader(os.path.join(bumper.data_dir, "web","templates")))
|
|
|
|
self.app.add_routes(
|
|
[
|
|
|
|
web.get("", self.handle_base, name="base"),
|
|
web.get("/bot/remove/{did}", self.handle_RemoveBot, name='remove-bot'),
|
|
web.get("/client/remove/{resource}", self.handle_RemoveClient, name='remove-client'),
|
|
web.get("/restart_{service}", self.handle_RestartService, name='restart-service'),
|
|
web.post("/lookup.do", self.handle_lookup),
|
|
|
|
]
|
|
)
|
|
|
|
# common api paths
|
|
api_v1 = {"prefix": "/v1/", "app": web.Application()} # for /v1/
|
|
api_v2 = {"prefix": "/v2/", "app": web.Application()} # for /v2/
|
|
portal_api = {"prefix": "/api/", "app": web.Application()} # for /api/
|
|
|
|
apis = {
|
|
"api_v1": api_v1,
|
|
"api_v2": api_v2,
|
|
"portal_api": portal_api,
|
|
|
|
}
|
|
|
|
# Load plugins
|
|
for plug in bumper.discovered_plugins:
|
|
if isinstance(bumper.discovered_plugins[plug].plugin, bumper.plugins.ConfServerApp):
|
|
plugin = bumper.discovered_plugins[plug].plugin
|
|
if plugin.plugin_type == "sub_api": # app or sub_api
|
|
if plugin.sub_api in apis:
|
|
if plugin.routes:
|
|
logging.debug(f"Adding confserver sub_api ({plugin.name})")
|
|
apis[plugin.sub_api]["app"].add_routes(plugin.routes)
|
|
|
|
elif plugin.plugin_type == "app":
|
|
if plugin.path_prefix and plugin.app:
|
|
logging.debug(f"Adding confserver plugin ({plugin.name})")
|
|
self.app.add_subapp(plugin.path_prefix, plugin.app)
|
|
|
|
for api in apis:
|
|
self.app.add_subapp(apis[api]["prefix"], apis[api]["app"])
|
|
|
|
for resource in self.app.router.resources():
|
|
print(resource)
|
|
|
|
|
|
|
|
async def start_site(self, app, address='localhost', port=8080, usessl=False):
|
|
runner = web.AppRunner(app)
|
|
self.runners.append(runner)
|
|
await runner.setup()
|
|
if 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,
|
|
host=address,
|
|
port=port,
|
|
ssl_context=ssl_ctx,
|
|
)
|
|
|
|
else:
|
|
site = web.TCPSite(
|
|
runner, host=address, port=port
|
|
)
|
|
|
|
await site.start()
|
|
|
|
async def start_server(self):
|
|
try:
|
|
confserverlog.info(
|
|
"Starting ConfServer at {}:{}".format(self.address[0], self.address[1])
|
|
)
|
|
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)
|
|
self.site = web.TCPSite(
|
|
self.runner,
|
|
host=self.address[0],
|
|
port=self.address[1],
|
|
ssl_context=ssl_ctx,
|
|
)
|
|
|
|
else:
|
|
self.site = web.TCPSite(
|
|
self.runner, host=self.address[0], port=self.address[1]
|
|
)
|
|
|
|
await self.site.start()
|
|
|
|
except PermissionError as e:
|
|
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))
|
|
|
|
async def handle_base(self, request):
|
|
try:
|
|
|
|
bots = bumper.db_get().table("bots").all()
|
|
clients = bumper.db_get().table("clients").all()
|
|
helperbot = bumper.mqtt_helperbot.Client.session.transitions.state
|
|
mqttserver = bumper.mqtt_server.broker
|
|
xmppserver = bumper.xmpp_server
|
|
mq_sessions = []
|
|
for sess in mqttserver._sessions:
|
|
tmpsess = []
|
|
tmpsess.append({
|
|
"username": mqttserver._sessions[sess][0].username,
|
|
"client_id": mqttserver._sessions[sess][0].client_id,
|
|
"state": mqttserver._sessions[sess][0].transitions.state,
|
|
})
|
|
|
|
mq_sessions.append(tmpsess)
|
|
all = {
|
|
"bots": bots,
|
|
"clients": clients,
|
|
"helperbot": [{"state": helperbot}],
|
|
"mqtt_server": [
|
|
{"state": mqttserver.transitions.state},
|
|
{
|
|
"sessions": [
|
|
{"count": len(mqttserver._sessions)},
|
|
{"clients": mq_sessions},
|
|
]
|
|
},
|
|
],
|
|
"xmpp_server": xmppserver
|
|
}
|
|
resp = aiohttp_jinja2.render_template('home.jinja2', request, context=all)
|
|
#return web.json_response(all)
|
|
return resp
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
@web.middleware
|
|
async def log_all_requests(self, request, handler):
|
|
|
|
if request._match_info.route.name not in self.excludelogging:
|
|
|
|
try:
|
|
if request.content_length:
|
|
if request.content_type == "application/x-www-form-urlencoded":
|
|
postbody = await request.post()
|
|
|
|
elif request.content_type == "application/json":
|
|
try:
|
|
postbody = json.loads(await request.text())
|
|
except Exception as e:
|
|
confserverlog.error("Request body not json: {} - {}".format(e, e.doc))
|
|
postbody = e.doc
|
|
|
|
else:
|
|
postbody = await request.post()
|
|
else:
|
|
postbody = None
|
|
|
|
response = await handler(request)
|
|
if not "application/octet-stream" in response.content_type:
|
|
logall = {
|
|
"request": {
|
|
"route_name": f"{request.match_info.route.name}",
|
|
"method": f"{request.method}",
|
|
"path": f"{request.path}",
|
|
"query_string": f"{request.query_string}",
|
|
"raw_path": f"{request.raw_path}",
|
|
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
"body": f"{postbody}",
|
|
},
|
|
|
|
"response": {
|
|
"response_body": f"{json.loads(response.body)}",
|
|
"status": f"{response.status}",
|
|
}
|
|
}
|
|
else:
|
|
logall = {
|
|
"request": {
|
|
"route_name": f"{request.match_info.route.name}",
|
|
"method": f"{request.method}",
|
|
"path": f"{request.path}",
|
|
"query_string": f"{request.query_string}",
|
|
"raw_path": f"{request.raw_path}",
|
|
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
"body": f"{postbody}",
|
|
},
|
|
|
|
"response": {
|
|
"status": f"{response.status}",
|
|
}
|
|
}
|
|
|
|
confserverlog.debug(json.dumps(logall))
|
|
|
|
return response
|
|
|
|
except web.HTTPNotFound as notfound:
|
|
confserverlog.debug("Request path {} not found".format(request.raw_path))
|
|
requestlog = {
|
|
"request": {
|
|
"route_name": f"{request.match_info.route.name}",
|
|
"method": f"{request.method}",
|
|
"path": f"{request.path}",
|
|
"query_string": f"{request.query_string}",
|
|
"raw_path": f"{request.raw_path}",
|
|
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
"body": f"{postbody}",
|
|
}
|
|
}
|
|
confserverlog.debug(json.dumps(requestlog))
|
|
return notfound
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
requestlog = {
|
|
"request": {
|
|
"route_name": f"{request.match_info.route.name}",
|
|
"method": f"{request.method}",
|
|
"path": f"{request.path}",
|
|
"query_string": f"{request.query_string}",
|
|
"raw_path": f"{request.raw_path}",
|
|
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
"body": f"{postbody}",
|
|
}
|
|
}
|
|
confserverlog.debug(json.dumps(requestlog))
|
|
return e
|
|
|
|
else:
|
|
return await handler(request)
|
|
|
|
async def restart_Helper(self):
|
|
|
|
await bumper.mqtt_helperbot.Client.disconnect()
|
|
asyncio.create_task(bumper.mqtt_helperbot.start_helper_bot())
|
|
|
|
async def restart_MQTT(self):
|
|
|
|
if not (bumper.mqtt_server.broker.transitions.state == "stopped" or bumper.mqtt_server.broker.transitions.state == "not_started"):
|
|
# close session writers - this was required so bots would reconnect properly after restarting
|
|
for sess in list(bumper.mqtt_server.broker._sessions):
|
|
sessobj = bumper.mqtt_server.broker._sessions[sess][1]
|
|
if sessobj.session.transitions.state == "connected":
|
|
await sessobj.writer.close()
|
|
|
|
#await bumper.mqtt_server.broker.shutdown()
|
|
aloop = asyncio.get_event_loop()
|
|
aloop.call_later(
|
|
0.1, lambda: asyncio.create_task(bumper.mqtt_server.broker.shutdown())
|
|
) # In .1 seconds shutdown broker
|
|
|
|
|
|
aloop = asyncio.get_event_loop()
|
|
aloop.call_later(
|
|
1.5, lambda: asyncio.create_task(bumper.mqtt_server.broker_coro())
|
|
) # In 1.5 seconds start broker
|
|
|
|
async def restart_XMPP(self):
|
|
bumper.xmpp_server.disconnect()
|
|
await bumper.xmpp_server.start_async_server()
|
|
|
|
async def handle_RestartService(self, request):
|
|
try:
|
|
service = request.match_info.get("service", "")
|
|
if service == "Helperbot":
|
|
await self.restart_Helper()
|
|
return web.json_response({"status": "complete"})
|
|
elif service == "MQTTServer":
|
|
asyncio.create_task(self.restart_MQTT())
|
|
aloop = asyncio.get_event_loop()
|
|
aloop.call_later(
|
|
5, lambda: asyncio.create_task(self.restart_Helper())
|
|
) # In 5 seconds restart Helperbot
|
|
|
|
return web.json_response({"status": "complete"})
|
|
elif service == "XMPPServer":
|
|
await self.restart_XMPP()
|
|
return web.json_response({"status": "complete"})
|
|
else:
|
|
return web.json_response({"status": "invalid service"})
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
pass
|
|
|
|
async def handle_RemoveBot(self, request):
|
|
try:
|
|
did = request.match_info.get("did", "")
|
|
bumper.bot_remove(did)
|
|
if bumper.bot_get(did):
|
|
return web.json_response({"status": "failed to remove bot"})
|
|
else:
|
|
return web.json_response({"status": "successfully removed bot"})
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
pass
|
|
|
|
async def handle_RemoveClient(self, request):
|
|
try:
|
|
resource = request.match_info.get("resource", "")
|
|
bumper.client_remove(resource)
|
|
if bumper.client_get(resource):
|
|
return web.json_response({"status": "failed to remove client"})
|
|
else:
|
|
return web.json_response({"status": "successfully removed client"})
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
pass
|
|
|
|
async def handle_login(self, request):
|
|
try:
|
|
user_devid = request.match_info.get("devid", "")
|
|
countrycode = request.match_info.get("country", "us")
|
|
apptype = request.match_info.get("apptype", "")
|
|
confserverlog.info(
|
|
"client with devid {} attempting login".format(user_devid)
|
|
)
|
|
if bumper.use_auth:
|
|
if (
|
|
not user_devid == ""
|
|
): # Performing basic "auth" using devid, super insecure
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
if "checkLogin" in request.path:
|
|
self.check_token(
|
|
apptype, countrycode, user, request.query["accessToken"]
|
|
)
|
|
else:
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(user["userid"])
|
|
login_details.loginName = "fusername_{}".format(
|
|
user["userid"]
|
|
)
|
|
login_details.mobile = None
|
|
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
# Deactivate old tokens and authcodes
|
|
bumper.user_revoke_expired_tokens(user["userid"])
|
|
|
|
login_details.accessToken = self.generate_token(user)
|
|
login_details.uid = "fuid_{}".format(user["userid"])
|
|
login_details.username = "fusername_{}".format(user["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
|
|
body = {
|
|
"code": API_ERRORS[RETURN_API_SUCCESS],
|
|
"data": json.loads(login_details.toJSON()),
|
|
# {
|
|
# "accessToken": self.generate_token(tmpuser), # Generate a token
|
|
# "country": countrycode,
|
|
# "email": "null@null.com",
|
|
# "uid": "fuid_{}".format(tmpuser["userid"]),
|
|
# "username": "fusername_{}".format(tmpuser["userid"]),
|
|
# },
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
body = {
|
|
"code": bumper.ERR_USER_NOT_ACTIVATED,
|
|
"data": None,
|
|
"msg": "当前密码错误",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
else:
|
|
return web.json_response(
|
|
self._auth_any(user_devid, apptype, countrycode, request)
|
|
)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
async def handle_lookup(self, request):
|
|
try:
|
|
|
|
body = {}
|
|
postbody = {}
|
|
if request.content_type == "application/x-www-form-urlencoded":
|
|
postbody = await request.post()
|
|
|
|
else:
|
|
postbody = json.loads(await request.text())
|
|
|
|
confserverlog.debug(postbody)
|
|
|
|
todo = postbody["todo"]
|
|
if todo == "FindBest":
|
|
service = postbody["service"]
|
|
if service == "EcoMsgNew":
|
|
srvip = bumper.bumper_announce_ip
|
|
srvport = 5223
|
|
confserverlog.info(
|
|
"Announcing EcoMsgNew Server to bot as: {}:{}".format(
|
|
srvip, 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(
|
|
"Announcing EcoUpdate Server to bot as: {}:{}".format(
|
|
srvip, srvport
|
|
)
|
|
)
|
|
body = {"result": "ok", "ip": srvip, "port": srvport}
|
|
|
|
return web.json_response(body)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
|
|
async def disconnect(self):
|
|
try:
|
|
confserverlog.info("shutting down")
|
|
await self.app.shutdown()
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
class ConfServer_GeneralFunctions:
|
|
def __init__(self):
|
|
pass
|
|
|
|
def get_milli_time(self, timetoconvert):
|
|
return int(round(timetoconvert * 1000))
|
|
|
|
class ConfServer_AuthHandler:
|
|
def __init__(self):
|
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
|
pass
|
|
|
|
def generate_token(self, user):
|
|
try:
|
|
tmpaccesstoken = uuid.uuid4().hex
|
|
bumper.user_add_token(user["userid"], tmpaccesstoken)
|
|
return tmpaccesstoken
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
def generate_authcode(self, user, countrycode, token):
|
|
try:
|
|
tmpauthcode = "{}_{}".format(countrycode, uuid.uuid4().hex)
|
|
bumper.user_add_authcode(user["userid"], token, tmpauthcode)
|
|
return tmpauthcode
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
|
|
async def login(self, request):
|
|
try:
|
|
user_devid = request.match_info.get("devid", "")
|
|
countrycode = request.match_info.get("country", "us")
|
|
apptype = request.match_info.get("apptype", "")
|
|
confserverlog.info(
|
|
"client with devid {} attempting login".format(user_devid)
|
|
)
|
|
if bumper.use_auth:
|
|
if (
|
|
not user_devid == ""
|
|
): # Performing basic "auth" using devid, super insecure
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
if "checkLogin" in request.path:
|
|
self.check_token(
|
|
apptype, countrycode, user, request.query["accessToken"]
|
|
)
|
|
else:
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(user["userid"])
|
|
login_details.loginName = "fusername_{}".format(
|
|
user["userid"]
|
|
)
|
|
login_details.mobile = None
|
|
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
# Deactivate old tokens and authcodes
|
|
bumper.user_revoke_expired_tokens(user["userid"])
|
|
|
|
login_details.accessToken = self.generate_token(user)
|
|
login_details.uid = "fuid_{}".format(user["userid"])
|
|
login_details.username = "fusername_{}".format(user["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
|
|
body = {
|
|
"code": API_ERRORS[RETURN_API_SUCCESS],
|
|
"data": json.loads(login_details.toJSON()),
|
|
# {
|
|
# "accessToken": self.generate_token(tmpuser), # Generate a token
|
|
# "country": countrycode,
|
|
# "email": "null@null.com",
|
|
# "uid": "fuid_{}".format(tmpuser["userid"]),
|
|
# "username": "fusername_{}".format(tmpuser["userid"]),
|
|
# },
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
body = {
|
|
"code": bumper.ERR_USER_NOT_ACTIVATED,
|
|
"data": None,
|
|
"msg": "当前密码错误",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
else:
|
|
return web.json_response(
|
|
self._auth_any(user_devid, apptype, countrycode, request)
|
|
)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
|
|
async def get_AuthCode(self, request):
|
|
try:
|
|
apptype = request.match_info.get("apptype", "")
|
|
user_devid = request.match_info.get("devid", "") # Ecovacs
|
|
if user_devid == "":
|
|
user_devid = request.query["deviceId"] # Ecovacs Home
|
|
|
|
if not user_devid == "":
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
token = ""
|
|
if user:
|
|
if "accessToken" in request.query:
|
|
token = bumper.user_get_token(
|
|
user["userid"], request.query["accessToken"]
|
|
)
|
|
if token:
|
|
authcode = ""
|
|
if not "authcode" in token:
|
|
authcode = self.generate_authcode(
|
|
user,
|
|
request.match_info.get("country", "us"),
|
|
request.query["accessToken"],
|
|
)
|
|
else:
|
|
authcode = token["authcode"]
|
|
if "global" in apptype:
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": {
|
|
"authCode": authcode,
|
|
"ecovacsUid": request.query["uid"],
|
|
},
|
|
"msg": "操作成功",
|
|
"success": True,
|
|
"time": self.get_milli_time(
|
|
datetime.utcnow().timestamp()
|
|
),
|
|
}
|
|
else:
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": {
|
|
"authCode": authcode,
|
|
"ecovacsUid": request.query["uid"],
|
|
},
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(
|
|
datetime.utcnow().timestamp()
|
|
),
|
|
}
|
|
return web.json_response(body)
|
|
|
|
body = {
|
|
"code": bumper.ERR_TOKEN_INVALID,
|
|
"data": None,
|
|
"msg": "当前密码错误",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
def check_token(self, apptype, countrycode, user, token):
|
|
try:
|
|
if bumper.check_token(user["userid"], token):
|
|
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(user["userid"])
|
|
login_details.loginName = "fusername_{}".format(user["userid"])
|
|
login_details.mobile = None
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
login_details.accessToken = token
|
|
login_details.uid = "fuid_{}".format(user["userid"])
|
|
login_details.username = "fusername_{}".format(user["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": json.loads(login_details.toJSON()),
|
|
# {
|
|
# "accessToken": self.generate_token(tmpuser), # Generate a token
|
|
# "country": countrycode,
|
|
# "email": "null@null.com",
|
|
# "uid": "fuid_{}".format(tmpuser["userid"]),
|
|
# "username": "fusername_{}".format(tmpuser["userid"]),
|
|
# },
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
return web.json_response(body)
|
|
|
|
else:
|
|
body = {
|
|
"code": bumper.ERR_TOKEN_INVALID,
|
|
"data": None,
|
|
"msg": "当前密码错误",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
return web.json_response(body)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
def _auth_any(self, devid, apptype, country, request):
|
|
try:
|
|
user_devid = devid
|
|
countrycode = country
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
bots = bumper.db_get().table("bots").all()
|
|
|
|
if user: # Default to user 0
|
|
tmpuser = user
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(tmpuser["userid"])
|
|
login_details.loginName = "fusername_{}".format(tmpuser["userid"])
|
|
login_details.mobile = None
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
login_details.accessToken = self.generate_token(tmpuser)
|
|
login_details.uid = "fuid_{}".format(tmpuser["userid"])
|
|
login_details.username = "fusername_{}".format(tmpuser["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
bumper.user_add_device(tmpuser["userid"], user_devid)
|
|
else:
|
|
bumper.user_add("tmpuser") # Add a new user
|
|
tmpuser = bumper.user_get("tmpuser")
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(tmpuser["userid"])
|
|
login_details.loginName = "fusername_{}".format(tmpuser["userid"])
|
|
login_details.mobile = None
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
login_details.accessToken = self.generate_token(tmpuser)
|
|
login_details.uid = "fuid_{}".format(tmpuser["userid"])
|
|
login_details.username = "fusername_{}".format(tmpuser["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
bumper.user_add_device(tmpuser["userid"], user_devid)
|
|
|
|
for bot in bots: # Add all bots to the user
|
|
if "did" in bot:
|
|
bumper.user_add_bot(tmpuser["userid"], bot["did"])
|
|
else:
|
|
confserverlog.error("No DID for bot: {}".format(bot))
|
|
|
|
if "checkLogin" in request.path: # If request was to check a token do so
|
|
checkToken = self.check_token(
|
|
apptype, countrycode, tmpuser, request.query["accessToken"]
|
|
)
|
|
isGood = json.loads(checkToken.text)
|
|
if isGood["code"] == "0000":
|
|
return isGood
|
|
|
|
# Deactivate old tokens and authcodes
|
|
bumper.user_revoke_expired_tokens(tmpuser["userid"])
|
|
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": json.loads(login_details.toJSON()),
|
|
# {
|
|
# "accessToken": self.generate_token(tmpuser), # Generate a token
|
|
# "country": countrycode,
|
|
# "email": "null@null.com",
|
|
# "uid": "fuid_{}".format(tmpuser["userid"]),
|
|
# "username": "fusername_{}".format(tmpuser["userid"]),
|
|
# },
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return body
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
|
|
def getUserAccountInfo(self, request):
|
|
try:
|
|
user_devid = request.match_info.get("devid", "")
|
|
countrycode = request.match_info.get("country", "us")
|
|
apptype = request.match_info.get("apptype", "")
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
|
|
if "global_" in apptype: # EcoVacs Home
|
|
login_details = EcoVacsHome_Login()
|
|
login_details.ucUid = "fuid_{}".format(user["userid"])
|
|
login_details.loginName = "fusername_{}".format(user["userid"])
|
|
login_details.mobile = None
|
|
else:
|
|
login_details = EcoVacs_Login()
|
|
|
|
login_details.uid = "fuid_{}".format(user["userid"])
|
|
login_details.username = "fusername_{}".format(user["userid"])
|
|
login_details.country = countrycode
|
|
login_details.email = "null@null.com"
|
|
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": {
|
|
"email": login_details.email,
|
|
"hasMobile": "N",
|
|
"hasPassword": "Y",
|
|
"uid": login_details.uid,
|
|
"userName": login_details.username,
|
|
"obfuscatedMobile": None,
|
|
"mobile": None,
|
|
"loginName": login_details.loginName,
|
|
},
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
return web.json_response(body)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e))
|
|
|
|
async def logout(self, request):
|
|
try:
|
|
user_devid = request.match_info.get("devid", "")
|
|
if not user_devid == "":
|
|
user = bumper.user_by_deviceid(user_devid)
|
|
if user:
|
|
if bumper.check_token(user["userid"], request.query["accessToken"]):
|
|
# Deactivate old tokens and authcodes
|
|
bumper.user_revoke_token(
|
|
user["userid"], request.query["accessToken"]
|
|
)
|
|
|
|
body = {
|
|
"code": bumper.RETURN_API_SUCCESS,
|
|
"data": None,
|
|
"msg": "操作成功",
|
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
|
}
|
|
|
|
return web.json_response(body)
|
|
|
|
except Exception as e:
|
|
confserverlog.exception("{}".format(e)) |