From 6c5bd3fe5dd5dc6eb9ad8d44c588e3cd8b01fdcd Mon Sep 17 00:00:00 2001 From: Jonathan Weth Date: Tue, 29 Jun 2021 16:35:33 +0200 Subject: Implement API handshake --- rwa/support/sessionservice/config.py | 4 ++ rwa/support/sessionservice/service.py | 88 ++++++++++++++++++++++++++++++++--- rwa/support/sessionservice/session.py | 3 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/rwa/support/sessionservice/config.py b/rwa/support/sessionservice/config.py index de5518d..7863751 100644 --- a/rwa/support/sessionservice/config.py +++ b/rwa/support/sessionservice/config.py @@ -28,3 +28,7 @@ import usersettings user_settings = usersettings.Settings("org.ArcticaProject.RWASupportSessionService") user_settings.add_setting("web_app_hosts", list, ["http://127.0.0.1:8000"]) user_settings.load_settings() + +SUPPORTED_API_VERSIONS = [1] +API_PATH = "/app/rwasupport/api/" +ALLOW_ONLY_ONE_SESSION = True diff --git a/rwa/support/sessionservice/service.py b/rwa/support/sessionservice/service.py index 52bf627..3305223 100755 --- a/rwa/support/sessionservice/service.py +++ b/rwa/support/sessionservice/service.py @@ -30,21 +30,20 @@ import logging import signal import time from threading import Thread -from typing import Union +from typing import Dict, Union import click import dbus import dbus.mainloop.glib import dbus.service +import requests from gi.repository import GLib -from .config import user_settings +from .config import ALLOW_ONLY_ONE_SESSION, API_PATH, SUPPORTED_API_VERSIONS, user_settings from .lock import is_locked, lock, unlock from .session import Session from .trigger import TriggerServerThread -ALLOW_ONLY_ONE_SESSION = True - class RWASupportSessionService(dbus.service.Object): """D-Bus Session Service for RWA.Support. @@ -99,6 +98,55 @@ class RWASupportSessionService(dbus.service.Object): """ return self._get_web_app_hosts() + def _do_api_handshake(self, host: str) -> Dict[str, str]: + """Contact a RWA.Support.WebApp host and find out API version. + + :param host: The full hostname. + :return: Status information as dictionary. + + **Structure of returned JSON (success):** + + :: + + {"status": "success", "type": "valid_host"} + + **Structure of returned JSON (error):** + + :: + + {"status": "error", "type": ""} + + **Possible choices for error types:** + + * ``connection`` + * ``permission_denied`` + * ``unsupported_server`` + """ + url = host + API_PATH + "handshake/" + logging.info(f"API handshake with {url} ...") + try: + r = requests.post(url) + + except requests.exceptions.ConnectionError: + logging.warning(" resulted in a connection error.") + return {"status": "error", "type": "connection"} + + if not r.ok: + logging.warning(" resulted in a connection error.") + return {"status": "error", "type": "connection"} + + if not r.json()["allowed"]: + logging.warning(" was not permitted.") + return {"status": "error", "type": "permission_denied"} + + if r.json().get("api_version") not in SUPPORTED_API_VERSIONS: + logging.warning(" resulted in a incompatible API version.") + return {"status": "error", "type": "unsupported_server"} + + logging.info(" was successful.") + + return {"status": "success", "type": "valid_host"} + @dbus.service.method( "org.ArcticaProject.RWASupportSessionService", in_signature="s", out_signature="s" ) @@ -108,12 +156,29 @@ class RWASupportSessionService(dbus.service.Object): :param host: Exact hostname of the RWA.Support.WebApp host (D-Bus string) :return: All registered hosts as JSON array (D-Bus string) - **Structure of returned JSON:** + **Structure of returned JSON (success):** :: ["https://example.org", "http://127.0.0.1:8000"] + + **Structure of returned JSON (error):** + + :: + + {"status": "error", "type": ""} + + **Possible choices for error types:** + + * ``connection`` + * ``permission_denied`` + * ``unsupported_server`` """ + # Check host by doing a handshake + res = self._do_api_handshake(host) + if res["status"] == "error": + return json.dumps(res) + user_settings.web_app_hosts.append(host) user_settings.save_settings() return self._get_web_app_hosts() @@ -158,7 +223,13 @@ class RWASupportSessionService(dbus.service.Object): {"status": "error", "type": ""} - **Possible choices for error types:** ``multiple``, ``connection`` + **Possible choices for error types:** + + * ``multiple`` + * ``connection`` + * ``host_not_found`` + * ``permission_denied`` + * ``unsupported_server`` """ if ALLOW_ONLY_ONE_SESSION and len(self.sessions.values()) > 0: logging.warning( @@ -174,6 +245,11 @@ class RWASupportSessionService(dbus.service.Object): except IndexError: return json.dumps({"status": "error", "type": "host_not_found"}) + # Check host by doing a handshake + res = self._do_api_handshake(host) + if res["status"] == "error": + return json.dumps(res) + # Start session try: session = Session(host, self.trigger_service.port, self.mockup_mode) diff --git a/rwa/support/sessionservice/session.py b/rwa/support/sessionservice/session.py index 0126800..aa97086 100644 --- a/rwa/support/sessionservice/session.py +++ b/rwa/support/sessionservice/session.py @@ -35,6 +35,7 @@ import port_for import psutil import requests +from .config import API_PATH from .lock import TEMP_DIR_PATH from .log import logging from .vnc import run_vnc, save_password @@ -59,7 +60,7 @@ class Session: def __init__(self, host: str, trigger_port: int, mockup_session: bool = False): self.host = host - self.BASE_URL = self.host + "/app/rwasupport/api/" + self.BASE_URL = self.host + API_PATH self.REGISTER_URL = self.BASE_URL + "register/" self.STOP_URL = self.BASE_URL + "stop/" self.STATUS_URL = self.BASE_URL + "status/" -- cgit v1.2.3