Ejemplo n.º 1
0
 def on_dispatcher_prepare(self, dispatcher: Dispatcher):
     for name in dir(self):
         item = getattr(self, name)
         if callable(item) and hasattr(item, ANNOTATIONS_RPC_METHOD_PROPERTY):
             rpc_name = getattr(item, ANNOTATIONS_RPC_METHOD_PROPERTY)
             if not getattr(item, ANNOTATIONS_IGNORE_PREFIX_PROPERTY, False):
                 rpc_name = self.METHOD_PREFXIX + rpc_name
             dispatcher.add_method(item, rpc_name)
Ejemplo n.º 2
0
def server_routine():
    d = Dispatcher()
    d.build_method_map(LibvirtController())
    # d.build_method_map(grpc.gRPCDataCollector())

    print("Collecting updates from server...")
    socket_sub.connect("tcp://localhost:%s" % port_sub)
    topicfilter = "test-id"
    socket_sub.setsockopt_string(zmq.SUBSCRIBE, topicfilter)
    while True:
        topic = socket_sub.recv().decode('ASCII')
        if socket_sub.get(zmq.RCVMORE) and topic == topicfilter:
            messagedata = socket_sub.recv()
            print(messagedata)
            pub_response(d, messagedata)
Ejemplo n.º 3
0
def master_state_service(args):
    # Start listening for connections
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', 31337))
    sock.listen()

    # Create order batch submission timer
    t = threading.Thread(target=sig_collector.send_batch_to_signer_services,
                         daemon=True)
    t.start()

    # Configure RPC dispatchers
    state_dispatchers = {
        State.RECEIVE_ORDERS:
        Dispatcher({"receive_order": client_handler.receive_order}),
        State.COLLECT_BATCH_SIGNATURES:
        Dispatcher({}),
        State.RETRIEVE_DKG_PK_FOR_ORDERS:
        Dispatcher({}),
        State.RECEIVE_MATCHES:
        Dispatcher({
            'receive_matching':
            matcher_handler.receive_matching,
            'return_latest_signed_batch':
            matcher_handler.return_latest_signed_batch
        }),
        State.COLLECT_MATCHINGS_SIGNATURES:
        Dispatcher({}),
        State.RETRIEVE_DKG_PK_FOR_MATCHINGS:
        Dispatcher({}),
        State.CHOOSE_OPTIMAL_MATCHING:
        Dispatcher({}),
    }
    global_dispatcher = Dispatcher({
        "return_confirmation":
        client_handler.return_confirmation,
        "return_matching_confirmation":
        matcher_handler.return_matching_confirmation,
    })

    # Accept connections and start handling them in own thread
    print("Gnodex Master State Server Started")
    while True:
        try:
            new_sock = sock.accept()[0]
            thread = threading.Thread(
                target=handle_rpc_client_stateful,
                args=(new_sock, certs.path_to('server.crt'),
                      certs.path_to('server.key'), state_dispatchers,
                      global_dispatcher, get_state_lock_func),
                daemon=True)
            thread.start()
        except KeyboardInterrupt:
            print("Master State Service Exit.")
            break
Ejemplo n.º 4
0
    def __init_api(self):
        self._req_disp = Dispatcher()

        def add_api_meth(api_f, name):
            # method format: <api_prefix>.<methodName>
            passid_api_f = lambda *args, **kwargs: api_f(self, *args, **kwargs)
            self._req_disp.add_method(
                passid_api_f, "{}.{}".format(PassIdApiServer.api_method_prefix,
                                             name))

        # register methods with @passidapi decorator as rpc api handler
        import inspect
        meths = inspect.getmembers(PassIdApiServer,
                                   predicate=inspect.isfunction)
        for m in meths:
            if m[1].__name__ == "wrapped_api_f":
                add_api_meth(m[1], m[0])
Ejemplo n.º 5
0
 def __init__(self, dispatcher: Dispatcher = None, expose_version_api=True, expose_ping_api=True) -> None:
     self.dispatcher = dispatcher or Dispatcher()
     self.__api_version = None  # type: str
     self.encoder = SizzleWSJsonEncoder()
     if expose_version_api:
         self.dispatcher[API_METHOD_VERSION] = self.m_get_version
     if expose_ping_api:
         self.dispatcher[API_METHOD_PING] = self.m_ping
     self.on_dispatcher_prepare(self.dispatcher)
Ejemplo n.º 6
0
def server_routine():
    d = Dispatcher()
    d.build_method_map(LibvirtController)
    d.build_method_map(gRPCDataCollector)
    d.build_method_map(DockerController)
    d.build_method_map(BCMController)

    print("Collecting updates from server...")
    socket_sub.connect("tcp://localhost:%s" % port_sub)
    topicfilter = CONTROLLER_ID
    socket_sub.setsockopt_string(zmq.SUBSCRIBE, topicfilter)
    while True:
        received = socket_sub.recv()
        pub_response(d, received)
Ejemplo n.º 7
0
def signer_service(args):
    # Start listening for connections
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', 31338 + signer.instance_id))
    sock.listen()

    # Configure RPC dispatchers
    state_dispatchers = {
        State.RECEIVE_ORDER_BATCH:
        Dispatcher({"receive_batch": server_handler.receive_order_batch}),
        State.RECEIVE_MATCH_COLLECTION:
        Dispatcher({
            "receive_match_collection":
            server_handler.receive_match_collection
        }),
    }
    global_dispatcher = Dispatcher({})

    # Accept connections and start handling them in own thread
    print("Gnodex Signing Service %d Started" % signer.instance_id)
    thread = threading.Thread(target=handle_rpc_state_changes,
                              args=(get_state_lock_func, set_state_func),
                              daemon=True)
    thread.start()
    while True:
        try:
            new_sock = sock.accept()[0]
            thread = threading.Thread(
                target=handle_rpc_client_stateful,
                args=(new_sock, certs.path_to('server.crt'),
                      certs.path_to('server.key'), state_dispatchers,
                      global_dispatcher, get_state_lock_func))
            thread.setDaemon(True)
            thread.start()
        except KeyboardInterrupt:
            print("Signing Service %d Exit." % signer.instance_id)
            break
Ejemplo n.º 8
0
    def __init__(
        self,
        app: Flask,
        *,
        path: str = "/api/",
        swagger_kwargs: Dict[str, Any] = None,
    ):
        """
        - `app` is a Flask app (https://flask.palletsprojects.com/en/1.1.x/)
            to which URL rules are added for the RPC.
        - `path` is the endpoint
            that will be added to the app for the JSON RPC.
            This is where requests will be POSTed.
            There will also be a path for each method based on the function name,
            e.g. `/api/scale` and `/api/translate`, see
            https://github.com/alexmojaki/instant_api#using-method-paths-instead-of-json-rpc
        - `swagger_kwargs` is a dictionary of keyword arguments
            to pass to the `flasgger.Swagger` constructor that is called with the app.
            For example, you can customise the Swagger UI by passing a dictionary to `config`
            (https://github.com/flasgger/flasgger#customize-default-configurations)::

                api = InstantAPI(app, swagger_kwargs={
                    "config": {"specs_route": "/my_apidocs/", ...}
                })
        """
        self.app = app
        self.path = path.rstrip("/") + "/"
        self.dispatcher = Dispatcher()
        self.swagger = Swagger(app, **(swagger_kwargs or {}))
        self._add_view(
            {"tags": ["JSON-RPC"]},
            GLOBAL_PARAMS_SCHEMA,
            GLOBAL_SUCCESS_SCHEMA,
            self.path,
            type(self).__name__,
            "Generic JSON RPC endpoint",
            method=None,
        )
Ejemplo n.º 9
0
    def __init__(self,
                 datamanager: "DataManager",
                 url: str,
                 port: int,
                 ConvertError: type,
                 ConflictError: type,
                 NotFoundError: type,
                 WouldBlockError: type,
                 callback=lambda r: None):
        super().__init__()
        self.datamanager = datamanager
        self.url = url
        self.port = port
        self.callback = callback
        self._define_errors()
        self.dispatcher = Dispatcher()
        self.setDaemon(True)

        @self.dispatcher.add_method
        def read(dataname: str):
            try:
                return {
                    dataname: self.datamanager.read_data(dataname),
                    'message': 'success'
                }
            except WouldBlockError as e:
                return self._error(e, self.WOULD_BLOCK_ERROR)
            except NotFoundError as e:
                return self._error(e, self.NOT_FOUND_ERROR)
            except ConvertError as e:
                # This mean unsupported type obj is requested
                # Users should regard this as not found error
                return self._error(e, self.NOT_FOUND_ERROR)
            except Exception as e:
                return self._error(e, self.INTERNAL_ERROR)

        @self.dispatcher.add_method
        def write(dataname: str, data: dict, provider: str = 'server'):
            try:
                self.datamanager.write_data(dataname, data, provider)
                return {'message': 'success'}
            except WouldBlockError as e:
                return self._error(e, self.WOULD_BLOCK_ERROR)
            except AssertionError as e:
                return self._error(e, self.INVALID_VALUE_ERROR)
            except ConflictError as e:
                return self._error(e, self.CONFLICT_ERROR)
            except Exception as e:
                return self._error(e, self.INTERNAL_ERROR)
Ejemplo n.º 10
0
 def __init__(self, handler, istream, ostream):
     self.handler = handler
     self.istream = istream
     self.ostream = ostream
     self.running = True
     self.dispatcher = Dispatcher({
         'initialize':
         self.initialize,
         'shutdown':
         self.shutdown,
         '$/setTraceNotification':
         self.setTraceNotification,
         'textDocument/didOpen':
         self.didOpen,
         'textDocument/didChange':
         self.didChange,
         'textDocument/hover':
         self.hover,
         'textDocument/definition':
         self.definition,
         'textDocument/completion':
         self.completion,
     })
Ejemplo n.º 11
0
class InstantAPI:
    """
    Instantly create an HTTP API with automatic type conversions, JSON RPC, and a Swagger UI. Just add methods!

    Basic usage looks like this::

        from dataclasses import dataclass
        from flask import Flask
        from instant_api import InstantAPI

        app = Flask(__name__)

        @dataclass
        class Point:
            x: int
            y: int

        @InstantAPI(app)
        class Methods:
            def translate(self, p: Point, dx: int, dy: int) -> Point:
                return Point(p.x + dx, p.y + dy)

            def scale(self, p: Point, factor: int) -> Point:
                return Point(p.x * factor, p.y * factor)

        if __name__ == '__main__':
            app.run()

    See the README at https://github.com/alexmojaki/instant_api for more details.

    Instances are callable so that they can be used as a decorator to add methods.
    See the docstring for __call__.

    You can subclass this class and override the following methods to customise behaviour:
        - is_authenticated
        - handle_request
        - call_method
    """
    def __init__(
        self,
        app: Flask,
        *,
        path: str = "/api/",
        swagger_kwargs: Dict[str, Any] = None,
    ):
        """
        - `app` is a Flask app (https://flask.palletsprojects.com/en/1.1.x/)
            to which URL rules are added for the RPC.
        - `path` is the endpoint
            that will be added to the app for the JSON RPC.
            This is where requests will be POSTed.
            There will also be a path for each method based on the function name,
            e.g. `/api/scale` and `/api/translate`, see
            https://github.com/alexmojaki/instant_api#using-method-paths-instead-of-json-rpc
        - `swagger_kwargs` is a dictionary of keyword arguments
            to pass to the `flasgger.Swagger` constructor that is called with the app.
            For example, you can customise the Swagger UI by passing a dictionary to `config`
            (https://github.com/flasgger/flasgger#customize-default-configurations)::

                api = InstantAPI(app, swagger_kwargs={
                    "config": {"specs_route": "/my_apidocs/", ...}
                })
        """
        self.app = app
        self.path = path.rstrip("/") + "/"
        self.dispatcher = Dispatcher()
        self.swagger = Swagger(app, **(swagger_kwargs or {}))
        self._add_view(
            {"tags": ["JSON-RPC"]},
            GLOBAL_PARAMS_SCHEMA,
            GLOBAL_SUCCESS_SCHEMA,
            self.path,
            type(self).__name__,
            "Generic JSON RPC endpoint",
            method=None,
        )

    def is_authenticated(self):
        """
        Override and return False for certain requests to deny any access to the API.
        """
        return True

    def handle_request(self, method: Optional[str]):
        """
        Entrypoint which converts a raw flask request to a response.

        If `method` is None, the request was made to the generic JSON-RPC path.
        Otherwise `method` is a string with the method name at the end of the request path.
        """
        if not self.is_authenticated():
            return "Forbidden", 403

        # Forward the request to the correct method
        # Ultimately this calls call_method
        request_data = request.get_data(as_text=True)
        if method is not None:
            request_data = ('{'
                            '   "id": null,'
                            '   "jsonrpc": "2.0",'
                            f'  "method": {json.dumps(method)},'
                            f'  "params": {request_data}'
                            '}')
        result = JSONRPCResponseManager.handle(request_data, self.dispatcher)

        if result is None:
            # Request was a notification, i.e. client doesn't need response
            return "", 200
        else:
            http_code = 200
            if result.error:
                data = result.error.get("data")
                # See the InstantError handler at the end of call_method
                if isinstance(data, dict) and "__instant_http_code" in data:
                    http_code = data["__instant_http_code"]
                    result.error["data"] = data["data"]
                else:
                    if result.error.get("code") in [
                            -32700,  # JSON parse error
                            -32600,  # Invalid JSON structure
                            -32602,  # Invalid params
                    ]:
                        http_code = 400  # Bad request
                    else:
                        http_code = 500  # Internal server error

            # JSON RPC must always return 200
            if method is None:
                http_code = 200

            return result.data, http_code

    def call_method(self, func, *args, **kwargs):
        """
        Calls the API method `func` with the given arguments.
        The arguments here are not yet deserialized according to the function type annotations.
        """
        try:
            try:
                return func(*args, **kwargs)
            except InstantError:
                raise
            except ArgumentError as e:
                e = e.__cause__
                if isinstance(e, ValidationError):
                    data = e.messages
                else:
                    data = None

                raise InstantError(
                    code=-32602,  # Invalid params
                    message=format_exception(e),
                    data=data,
                    http_code=400,
                )
            except JSONRPCDispatchException as e:
                raise InstantError(
                    code=e.error.code,
                    message=e.error.message,
                    data=e.error.data,
                )
            except Exception:
                raise InstantError(
                    code=-32000,
                    message=f"Unhandled error in method {func.__name__}",
                )
        except InstantError as e:
            raise JSONRPCDispatchException(
                code=e.code,
                message=e.message,
                # Mash the http_code in here to be extracted later in handle_request
                # There's no easy way to get this info through the json-rpc
                # library up to the final response
                data=dict(
                    __instant_http_code=e.http_code,
                    data=e.data,
                ),
            )

    def __call__(self,
                 func_class_or_obj: Any = None,
                 *,
                 swagger_view_attrs: dict = None):
        """
        Accepts any object, with special treatment for functions and classes,
        so this can be used as a decorator.

        Decorating a single function adds it as an API method.
        The function itself should not be a method of a class,
        since there is no way to provide the first argument `self`.

        Decorating a class will construct an instance of the class without arguments
        and then call the resulting object as described below.
        This means it will add bound methods, so the `self` argument is ignored.

        Passing an object will search through all its attributes
        and add to the API all functions (including bound methods)
        whose name doesn't start with an underscore (`_`).

        So given `api = InstantAPI(app)`, all of these are equivalent:

            @api
            def foo(bar: Bar) -> Spam:
                ...

            api(foo)

            @api
            class Methods:
                def foo(self, bar: Bar) -> Spam:
                    ...

            api(Methods)

            api(Methods())

        If a function is missing a type annotation for any of its parameters or for the return value,
        an exception will be raised.
        If you don't want a method to be added to the API,
        prefix its name with an underscore, e.g. `def _foo(...)`.

        For each function, a `flasgger.SwaggerView` will be created.
        (see https://github.com/flasgger/flasgger#using-marshmallow-schemas)
        You can customise the view by passing a dictionary class attributes
        in the argument `swagger_view_attrs`
        For example::

            @api(swagger_view_attrs={"tags": ["Stuff"]})
            def foo(...)

        This will put `foo` in the `Stuff` section of the Swagger UI.

        If a function has a docstring, its first line will be the "summary"
        in the OpenAPI spec of the method path, visible in the overview in the Swagger UI.
        The remaining lines will become the "description",
        visible when the path is expanded in the UI.
        """

        if func_class_or_obj is None:
            # Decorator with arguments
            return functools.partial(self,
                                     swagger_view_attrs=swagger_view_attrs)

        if isinstance(func_class_or_obj, type):
            cls = func_class_or_obj
            self(cls(), swagger_view_attrs=swagger_view_attrs)
            return cls

        # noinspection PyTypeChecker
        self._decorate_function(func_class_or_obj, swagger_view_attrs)
        methods = func_class_or_obj
        for name, func in inspect.getmembers(methods):
            if not name.startswith("_"):
                self._decorate_function(func, swagger_view_attrs)

        return func_class_or_obj

    def _decorate_function(self, func, swagger_view_attrs):
        try:
            inspect.signature(func)
        except Exception:
            return

        name = func.__name__
        func: datafunction = datafunction(func)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return self.call_method(func, *args, **kwargs)

        self.dispatcher.add_method(wrapper)

        @dataclass
        class _Success:
            id: int
            jsonrpc: str

        class Success(class_schema(_Success)):
            result = func.return_schemas.schema_class._declared_fields[
                "_return"]

        Success.__name__ = f"{name}_success"

        self._add_view(
            swagger_view_attrs or {},
            func.params_schemas.schema_class,
            Success,
            self.path + name,
            type(self).__name__ + "_" + name,
            func.__doc__,
            method=name,
        )

    def _add_view(
        self,
        swagger_view_attrs: dict,
        body_schema,
        success_schema,
        path: str,
        view_name: str,
        doc: str,
        method: Optional[str],
    ):
        instant_api_self = self

        class MethodView(SwaggerView):
            summary, _, description = dedent(doc or "").strip().partition("\n")
            parameters = [{
                "name": "body",
                "in": "body",
                "schema": body_schema,
                "required": True,
            }]
            responses = {
                "Success": {
                    "schema": success_schema
                },
                "Error": {
                    "schema": ERROR_SCHEMA
                },
            }
            tags = ["Methods"]

            locals().update(swagger_view_attrs)

            def post(self):
                return instant_api_self.handle_request(method)

        self.app.add_url_rule(
            path,
            view_func=MethodView.as_view(view_name),
            methods=["POST"],
        )
Ejemplo n.º 12
0
def rpc_server_worker(host, port, username, password, queue):
    dispatcher = Dispatcher()
    srv = None
    # prehash password
    password = int(sha256(bytes(password, "utf8")).hexdigest(), 16)

    @dispatcher.add_method
    def actions(args):
        try:
            actionlist = args[0]
            for action in actionlist:
                if action[0] not in ('mousemove', 'mousebutton', 'keyevent'):
                    raise ValueError('unknown action')
            queue.put((None, 'actions', actionlist), True)
            return "OK"
        except:
            return "UNEXPECTED_INPUT"

    @dispatcher.add_method
    def mousebutton(args):
        respqueue = Queue(1)
        queue.put((respqueue, "mousebutton") + tuple(args), True)
        try:
            return respqueue.get(True, 5)
        except QueueEmpty:
            return "TIMEOUT"

    @dispatcher.add_method
    def mousemove(args):
        respqueue = Queue(1)
        queue.put((respqueue, "mousemove") + tuple(args), True)
        try:
            return respqueue.get(True, 5)
        except QueueEmpty:
            return "TIMEOUT"

    @dispatcher.add_method
    def keyevent(args):
        key, modifiers, down = args
        respqueue = Queue(1)
        queue.put((respqueue, "keyevent", key, modifiers or [], down), True)
        try:
            return respqueue.get(True, 5)
        except QueueEmpty:
            return "TIMEOUT"

    @dispatcher.add_method
    def devicecommand(args):
        devcommand = args
        respqueue = Queue(1)
        queue.put((respqueue, "devicecommand", devcommand), True)
        try:
            return respqueue.get(True, 5)
        except QueueEmpty:
            return "TIMEOUT"

    @dispatcher.add_method
    def exit(args):
        respqueue = Queue(1)
        queue.put((respqueue, "exit"), True)
        try:
            respqueue.get(True, 5)
        except:
            pass
        raise RPCServExitException()

    @Request.application
    def app(request):
        # auth with simplified version of equal op (timing attack secure)
        if (username != "" or password != "") and \
           (getattr(request.authorization,"username","") != username or \
            int(sha256(bytes(getattr(request.authorization,"password",""), "utf8")).hexdigest(), 16) - \
            password != 0):
            json = JSONRPC20Response(error={
                "code": 403,
                "message": "Invalid username or password!"
            }).json
            return Response(json, 403, mimetype='application/json')
        response = JSONRPCResponseManager.handle(request.data, dispatcher)
        return Response(response.json, mimetype='application/json')

    try:
        # response queue is used to notify result of attempt to run the server
        respqueue = queue.get()
        srv = make_server(host, port, app, request_handler=RequestHandler)
        logging.info("http-jsonrpc listening at {}:{}".format(host, port))
        queue.task_done()  # let run_rpc_server return
        respqueue.put("SUCCESS")
        srv.serve_forever()
    except RPCServExitException:
        logging.info("Exit exception raised!")
    except:
        queue.task_done()
        respqueue.put("FAIL")
        logging.error(traceback.format_exc())
Ejemplo n.º 13
0
import psycopg2
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple

from jsonrpc import JSONRPCResponseManager, dispatcher, Dispatcher

dispatcher = Dispatcher()


@dispatcher.add_method
def example_method(*args, **kwargs):
    print("param 1: " + args[0])
    print("param 2: " + args[1])


@dispatcher.add_method
def connect_to_db(*args, **kwargs):
    try:
        connect_str = "dbname='pos_projekt' user='******' host='X' password='******'"
        # use our connection values to establish a connection
        conn = psycopg2.connect(connect_str)
        # create a psycopg2 cursor that can execute queries
        cursor = conn.cursor()
        # create a new table with a single column called "name"
        # cursor.execute("""CREATE TABLE tutorials (name char(40));""")
        # run a SELECT statement - no data in there, but we can try it
        cursor.execute("""SELECT * from User""")
        rows = cursor.fetchall()
        print(rows)
    except Exception as e:
        print("Uh oh, can't connect. Invalid dbname, user or password?")
Ejemplo n.º 14
0
 def __init__(self, *args, **kwargs):
     message_handler = MessageHandler(kwargs.pop('to_printer'))
     self.dispatcher = Dispatcher(message_handler)
     super().__init__(*args, **kwargs)
Ejemplo n.º 15
0
class PassIdApiServer:
    """ PassID Api server """
    api_method_prefix = "passID"

    def __init__(self, db: proto.StorageAPI, config: Config):
        self._conf = config.api_server
        self._proto = proto.PassIdProto(db, config.challenge_ttl)
        self._log = log.getLogger("passid.api")

        # Register rpc api methods
        self.__init_api()

    def start(self):
        run_simple(self._conf.host,
                   self._conf.port,
                   self.__create_calls,
                   ssl_context=self._conf.ssl_ctx,
                   threaded=True)

    def passidapi(api_f):
        def wrapped_api_f(self, *args, **kwargs):
            self.__log_api_call(api_f, **kwargs)
            ret = api_f(self, *args, **kwargs)
            self.__log_api_response(api_f, ret)
            return ret

        return wrapped_api_f

# RPC API methods
# API: passID.ping

    @passidapi
    def ping(self, ping: int) -> dict:
        """ 
        Function returns challenge that passport needs to sign.
        Challenge is base64 encoded.
        """
        try:
            pong = int.from_bytes(os.urandom(4), 'big')
            return {"pong": pong}
        except Exception as e:
            return self.__handle_exception(e)

    # API: passID.getChallenge
    @passidapi
    def getChallenge(self) -> dict:
        """ 
        Function returns challenge that passport needs to sign.
        Challenge is base64 encoded.
        """
        try:
            c = self._proto.createNewChallenge()
            return {"challenge": c.toBase64()}
        except Exception as e:
            return self.__handle_exception(e)

    # API: passID.cancelChallenge
    @passidapi
    def cancelChallenge(self, challenge: str) -> Union[None, dict]:
        """ 
        Function erases challenge from server.
        :param challenge: base64 encoded string
        :return: 
                 Nothing if success, else error
        """
        try:
            challenge = try_deser(
                lambda: proto.Challenge.fromBase64(challenge))
            self._proto.cancelChallenge(challenge.id)
            return None
        except Exception as e:
            return self.__handle_exception(e)

    # API: passID.register
    @passidapi
    def register(self,
                 dg15: str,
                 sod: str,
                 cid: str,
                 csigs: List[str],
                 dg14: str = None) -> dict:
        """ 
        Register new user. It returns back to the client userId which is publicKey address,
        session key and session expiration time.

        :param dg15: eMRTD DG15 file
        :param sod: eMRTD SOD file
        :param cid: Challenge id
        :param csigs: Challenge signatures
        :param dg14: eMRTD DG14 file (optional)
        :return: 
                 'uid'         - base64 encoded user id
                 'session_key' - base64 encoded session key
                 'expires'     - unix timestamp of time when session will expire
        """

        try:
            dg15 = try_deser(lambda: ef.DG15.load(b64decode(dg15)))
            sod = try_deser(lambda: ef.SOD.load(b64decode(sod)))
            cid = try_deser(lambda: proto.CID.fromhex(cid))
            csigs = _b64csigs_to_bcsigs(csigs)
            if dg14 is not None:
                dg14 = try_deser(lambda: ef.DG14.load(b64decode(dg14)))

            uid, sk, set = self._proto.register(dg15, sod, cid, csigs, dg14)
            return {
                "uid": uid.toBase64(),
                "session_key": sk.toBase64(),
                "expires": int(set.timestamp())
            }
        except Exception as e:
            return self.__handle_exception(e)

    # API: passID.login
    @passidapi
    def login(self,
              uid: str,
              cid: str,
              csigs: List[str],
              dg1: str = None) -> dict:
        """ 
        It returns back session key and session expiration time.

        :param uid: User id
        :param cid: Challenge id
        :param csigs: Challenge signatures
        :return:
                 'session_key' - base64 encoded session key
                 'expires'     - unix timestamp of time when session will expire
        """
        try:
            uid = try_deser(lambda: proto.UserId.fromBase64(uid))
            cid = try_deser(lambda: proto.CID.fromhex(cid))
            csigs = _b64csigs_to_bcsigs(csigs)
            if dg1 is not None:
                dg1 = try_deser(lambda: ef.DG1.load(b64decode(dg1)))

            sk, set = self._proto.login(uid, cid, csigs, dg1)
            return {
                "session_key": sk.toBase64(),
                "expires": int(set.timestamp())
            }
        except Exception as e:
            return self.__handle_exception(e)

    # API: passID.sayHello
    @passidapi
    def sayHello(self, uid: str, mac: str) -> dict:
        """ 
        It returns back greeting message based on whether user is anonymous or not.

        :param uid: User id
        :param mac: session mac over api name and uid
        :return:
                 'msg' - greeting message
        """
        try:
            uid = try_deser(lambda: proto.UserId.fromBase64(uid))
            mac = try_deser(lambda: b64decode(mac))
            msg = self._proto.sayHello(uid, mac)
            return {"msg": msg}
        except Exception as e:
            return self.__handle_exception(e)

# Request handler

    @Request.application
    def __create_calls(self, request):
        """Create API calls"""
        response = JRPCRespMgr.handle(request.data, self._req_disp)
        if response is not None:
            return Response(response.json, mimetype='application/json')
        return Response()

    def __handle_exception(self, e: Exception) -> dict:
        if isinstance(e, proto.ProtoError):
            self._log.debug("Request proto error: {}".format(e))
            raise JSONRPCDispatchException(e.code, str(e))

        if isinstance(e, proto.SeEntryNotFound):
            self._log.debug("Request storage error: {}".format(e))
            raise JSONRPCDispatchException(404, str(e))

        self._log.error("Unhandled exception encountered, e={}".format(e))
        raise JSONRPCDispatchException(500, "Internal Server Error")

    def __init_api(self):
        self._req_disp = Dispatcher()

        def add_api_meth(api_f, name):
            # method format: <api_prefix>.<methodName>
            passid_api_f = lambda *args, **kwargs: api_f(self, *args, **kwargs)
            self._req_disp.add_method(
                passid_api_f, "{}.{}".format(PassIdApiServer.api_method_prefix,
                                             name))

        # register methods with @passidapi decorator as rpc api handler
        import inspect
        meths = inspect.getmembers(PassIdApiServer,
                                   predicate=inspect.isfunction)
        for m in meths:
            if m[1].__name__ == "wrapped_api_f":
                add_api_meth(m[1], m[0])

    def __log_api_call(self, f, **kwargs):
        if self._log.level <= log.VERBOSE:
            self._log.debug(":{}() ==>".format(f.__name__))
            for a, v in kwargs.items():
                self._log.verbose(" {}: {}".format(a, v))

    def __log_api_response(self, f, resp: dict):
        if self._log.level <= log.VERBOSE:
            self._log.debug(":{}() <==".format(f.__name__))
            if (resp is not None):
                for a, v in resp.items():
                    self._log.verbose(" {}: {}".format(a, v))
Ejemplo n.º 16
0
    def __init__(self, server, connection) -> None:
        super().__init__()

        self.__server = server  # type: LanguageTCPServer
        self.__connection = connection
        self.__reader = connection.makefile('r')
        self.__writer = connection.makefile('w')
        self.__workspace = None

        dispatcher = Dispatcher()
        self.dispatcher = dispatcher

        dispatcher.add_method(self.initialize)
        dispatcher.add_method(self.initialized)
        dispatcher.add_method(self.workspace_change_config,
                              'workspace/didChangeConfiguration')
        dispatcher.add_method(self.text_document_open, 'textDocument/didOpen')
        dispatcher.add_method(self.text_document_change,
                              'textDocument/didChange')
        dispatcher.add_method(self.text_document_close,
                              'textDocument/didClose')
        dispatcher.add_method(self.text_document_completion,
                              'textDocument/completion')
Ejemplo n.º 17
0
 def on_dispatcher_prepare(self, dispatcher: Dispatcher):
     dispatcher.build_method_map(self, self.METHOD_PREFXIX)
Ejemplo n.º 18
0
        return usr.to_dict()

    @classmethod
    def get_username(cls):
        if cls.user:
            return cls.user.name
        return None


dispatcher = Dispatcher(
    {
        "create_chat": RPC.create_chat,
        "list_chats": RPC.list_chats,
        "create_message": RPC.create_message,
        "list_messages": lambda **kwargs: RPC.list_messages(
            kwargs["chat"], kwargs.get("start"), kwargs.get("end"), kwargs.get("last")
        ),
        "join_chat": RPC.join_chat,
        "register": RPC.register,
        "search_chats": RPC.search_chats,
        "get_username": RPC.get_username
    }
)


def entry_point(request: flask.Request = None):
    """
    Entrypoint rpc. flask view
    :param request:
    :return:
    """
    if not request: