예제 #1
0
        async def get_long_lived_token(
                request: web.Request) -> JSONResponse:
            """
            Generates a long-lived access token
            This token will be valid for 10 years
            """
            try:
                data = vol.Schema({
                    vol.Required("client_id"): str,
                    vol.Optional(
                        "client_name", default=None): vol.Any(str, None)
                })(await request.json())
            except (vol.Invalid, JSONDecodeError) as e:
                return JSONResponse(error=str(e))

            refresh_token = await self.auth_manager.create_refresh_token(
                client_id=data["client_id"],
                user=request.user,
                access_token_expiration=timedelta(days=3650),
                client_name=data["client_name"]
            )
            access_token = await self.auth_manager.create_access_token(
                refresh_token)

            return JSONResponse({
                "access_token": access_token.token,
                "token_type": "bearer",
                "expires_in": access_token.expiration,
                "refresh_token": refresh_token.token,
            }, headers={
                "Cache-Control": "no-store"
            })
예제 #2
0
    async def post(self) -> JSONResponse:
        """POST /bind_credentials"""
        try:
            data = vol.Schema({
                vol.Required("provider", default="password"):
                vol.Any(*self.auth_manager.credential_providers.keys()),
                vol.Optional("user", default=None):
                vol.Any(str, None),
                vol.Optional("data", default=None):
                object
            })(await self.request.json())
        except (vol.Invalid, JSONDecodeError) as e:
            return JSONResponse(error=str(e))

        if data["user"] and not self.request["user"].owner:
            return JSONResponse(error="Unauthorized", status_code=401)

        user = self.auth_manager.get_user(data["user"]) or self.request["user"]

        provider: "CredentialProvider" = (
            self.auth_manager.credential_providers[data["provider"]])

        creds, return_data = await provider.create_credentials(
            user, data["data"])
        self.auth_manager.users.schedule_save()

        return JSONResponse({
            "credential_id": creds.credential_id,
            "data": return_data
        })
예제 #3
0
        async def get_item_state(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            state_name = request.match_info["state_name"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            if state_name not in item.states.states:
                return JSONResponse(
                    error={
                        "type":
                        ITEM_STATE_NOT_FOUND,
                        "message":
                        f"Couldn't get state {state_name}"
                        f"from item {identifier}"
                    })

            return JSONResponse({
                "item": item,
                "type": item.type,
                "states": {
                    state_name: await item.states.get(state_name)
                }
            })
예제 #4
0
    async def post(self) -> JSONResponse:
        """POST /item/{id}/states"""
        identifier = self.data["id"]
        item = self.core.item_manager.items.get(identifier)

        if not item:
            return self.error(
                ERROR_ITEM_NOT_FOUND,
                f"No item found with identifier {identifier}", 404)

        try:
            content = (await self.request.content.read()).decode()
            commit = STATE_COMMIT_SCHEMA(
                json.loads(content) if content else {})
        # pylint: disable=broad-except
        except Exception as e:
            return JSONResponse(error=e)

        if not commit.keys() & item.states.states.keys() == commit.keys():
            return self.error(
                ERROR_INVALID_ITEM_STATES,
                f"The given states {set(commit.keys())} do not comply with "
                f"accepted states {set(item.states.states.keys())}")

        if not item.status == ItemStatus.ONLINE:
            return JSONResponse(
                error=ItemNotOnlineError(
                    f"The item {item.identifier} is not online"))

        return JSONResponse(dict(ChainMap(
            *[await item.states.set(state, value)
              for state, value in commit.items()])))
예제 #5
0
        async def get_actions(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)
            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            return JSONResponse(data=list(item.actions.actions.keys()))
예제 #6
0
        async def do_login_flow_step(request: web.Request) -> JSONResponse:
            """Executes the current login_flow step"""
            try:
                data = await request.json()
            except JSONDecodeError as e:
                return JSONResponse(error=str(e))

            flow = self.flow_manager.flows.get(request.match_info["flow_id"])

            if not flow:
                return JSONResponse(error="Login flow does not exist")

            step = flow.get_step(flow.current_step)
            step_result = await step(data)

            return JSONResponse(step_result.to_json())
예제 #7
0
    async def post(self) -> JSONResponse:
        """POST /long_lived_token"""
        try:
            data = vol.Schema({
                vol.Required("client_id"):
                str,
                vol.Optional("client_name", default=None):
                vol.Any(str, None)
            })(await self.request.json())
        except (vol.Invalid, JSONDecodeError) as e:
            return self.error(e)

        refresh_token = await self.auth_manager.create_refresh_token(
            client_id=data["client_id"],
            user=self.request["user"],
            access_token_expiration=timedelta(days=3650),
            client_name=data["client_name"])
        access_token = await self.auth_manager.create_access_token(
            refresh_token)

        return JSONResponse(
            {
                "access_token": access_token.token,
                "token_type": "bearer",
                "expires_in": access_token.expiration,
                "refresh_token": refresh_token.token,
            },
            headers={"Cache-Control": "no-store"})
예제 #8
0
        async def execute_action(request: web.Request) -> JSONResponse:
            """
            Executes an item's action and returns a boolean indicating the
            success of the action. Changed states or other events can be
            handled through the websocket endpoint /events
            """

            identifier = request.match_info["id"]
            action_name = request.match_info["action_name"]
            item = self.core.item_manager.items.get(identifier)
            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            try:
                content = (await request.content.read()).decode()
                kwargs = json.loads(content) if content else {}
            except JSONDecodeError as e:
                return JSONResponse(error=e)

            if action_name not in item.actions.actions:
                return JSONResponse(
                    error={
                        "type":
                        ITEM_ACTION_NOT_FOUND,
                        "message":
                        f"Item {identifier} of type {item.type} "
                        f"does not have an action {action_name}"
                    })

            try:
                return JSONResponse({
                    "item":
                    item,
                    "action":
                    action_name,
                    "result":
                    await item.actions.execute(action_name, **kwargs)
                })
            # pylint: disable=broad-except
            except Exception as e:
                return JSONResponse(error=e)
예제 #9
0
파일: module.py 프로젝트: zuurw/HomeControl
        async def get_event_log_by_type(request: web.Request) -> JSONResponse:
            event_type = request.match_info["type"]

            with self.session_context() as session:
                result = session.query(models.EventLog).filter(
                    models.EventLog.event_type == event_type)

            return JSONResponse(result.all())
예제 #10
0
        async def get_item_states(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            return JSONResponse({
                "item": item,
                "type": item.type,
                "states": await item.states.dump(),
            })
예제 #11
0
 def json(self,
          data: Any = None,
          status_code: int = 200,
          headers: dict = None) -> JSONResponse:
     """Creates a JSONResponse"""
     return JSONResponse(data,
                         status_code=status_code,
                         core=self.core,
                         headers=headers)
예제 #12
0
        async def reload_item(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            await self.core.item_manager.recreate_item(item)

            return JSONResponse({
                "message": f"Item {identifier} recreated",
                "status": item.status.value
            })
예제 #13
0
 async def get_items(request: web.Request) -> JSONResponse:
     return JSONResponse([{
         "id": item.identifier,
         "name": item.name,
         "type": item.type,
         "module": item.module.name,
         "status": item.status.value,
         "actions": list(item.actions.actions.keys()),
         "states": await item.states.dump()
     } for item in self.core.item_manager.items.values()])
예제 #14
0
        async def set_item_states(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            try:
                content = (await request.content.read()).decode()
                commit = STATE_COMMIT_SCHEMA(
                    json.loads(content) if content else {})
            # pylint: disable=broad-except
            except Exception as e:
                return JSONResponse(error=e)

            if not commit.keys() & item.states.states.keys() == commit.keys():
                return JSONResponse(
                    error={
                        "type":
                        ERROR_INVALID_ITEM_STATES,
                        "message":
                        f"The given states {set(commit.keys())} do not"
                        f"comply with accepted states "
                        f"{set(item.states.states.keys())}"
                    })

            if not item.status == ItemStatus.ONLINE:
                return JSONResponse(error=ItemNotOnlineError(
                    f"The item {item.identifier} is not online"))

            return JSONResponse(
                dict(
                    ChainMap(*[
                        await item.states.set(state, value)
                        for state, value in commit.items()
                    ])))
예제 #15
0
        async def create_login_flow(request: web.Request) -> JSONResponse:
            """Creates a login flow"""
            try:
                data = vol.Schema({
                    vol.Required("provider"): vol.Any(
                        *self.flow_manager.flow_factories.keys()),
                    vol.Required("client_id"): str
                })(await request.json())
            except (vol.Invalid, JSONDecodeError) as e:
                return JSONResponse(error=str(e))

            flow = await self.flow_manager.create_flow(
                data["provider"],
                data["client_id"])
            if not flow:
                return JSONResponse(error="Login flow does not exist")

            first_result = await flow.step_init(data)

            return JSONResponse(first_result.to_json())
예제 #16
0
        async def get_item(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            return JSONResponse({
                "id": item.identifier,
                "type": item.type,
                "module": item.module.name,
                "config": item.cfg,
                "status": item.status.value
            })
예제 #17
0
파일: module.py 프로젝트: zuurw/HomeControl
        async def get_state_log(request: web.Request) -> JSONResponse:
            identifier = request.match_info["item"]
            state_name = request.query.get("state", None)

            with self.session_context() as session:
                result = session.query(models.StateLog).filter(
                    models.StateLog.item_identifier == identifier)
                if state_name:
                    result = result.filter(
                        models.StateLog.state_name == state_name)

            return JSONResponse(result.all())
예제 #18
0
 def error(self,
           error: Union[str, Exception],
           message: str = None,
           status_code: int = 500) -> JSONResponse:
     """Creates an error message"""
     return JSONResponse(error={
         "type": type(error).__name__,
         "message": str(error)
     } if isinstance(error, Exception) else {
         "type": error,
         "message": message
     },
                         status_code=status_code)
예제 #19
0
        async def set_item_state(request: web.Request) -> JSONResponse:
            identifier = request.match_info["id"]
            item = self.core.item_manager.items.get(identifier)

            if not item:
                return JSONResponse(error={
                    "type":
                    ERROR_ITEM_NOT_FOUND,
                    "message":
                    f"No item found with identifier {identifier}"
                },
                                    status_code=404)

            state_name = request.match_info["state_name"]

            if state_name not in item.states.states.keys():
                return JSONResponse(
                    error={
                        "type": ERROR_INVALID_ITEM_STATE,
                        "message":
                        f"The given state '{state_name}' does not exist"
                    })

            if not item.status == ItemStatus.ONLINE:
                return JSONResponse(error=ItemNotOnlineError(
                    f"The item {item.identifier} is not online"))

            try:
                content = (await request.content.read()).decode()
                value = json.loads(content) if content else {}
                result = await item.states.set(state_name, value)
            # pylint: disable=broad-except
            except (Exception, vol.error.Error) as e:
                return JSONResponse(error=e)

            return JSONResponse(result)
예제 #20
0
        async def create_user(request: web.Request) -> JSONResponse:
            """Creates a user"""
            payload_schema = vol.Schema({
                vol.Required("name"): str,
                vol.Required("password"): str,
                vol.Optional("is_owner", default=False): bool,
            })
            payload = payload_schema(await request.json())

            user = await self.auth_manager.create_user(
                name=payload["name"],
                owner=payload["is_owner"]
            )

            provider: CredentialProvider = (
                self.auth_manager.credential_providers["password"])

            await provider.create_credentials(user, payload["password"])

            self.auth_manager.users.schedule_save()

            return JSONResponse({
                "user_id": user.id
            })
예제 #21
0
 async def ping(request: web.Request) -> JSONResponse:
     """Handle /ping"""
     return JSONResponse("PONG")
예제 #22
0
    async def post(self) -> JSONResponse:
        """POST /token"""
        try:
            data = dict((await self.request.post()).items())
            payload = TOKEN_PAYLOAD_SCHEMA(data)
        except vol.Invalid as e:
            path = ', '.join(str(var) for var in e.path)
            return self.json(
                {
                    "error": "invalid_request",
                    "error_description": f"Invalid parameters: {path}"
                },
                status_code=400)

        if payload["grant_type"] == "code":
            try:
                payload = AUTH_CODE_SCHEMA(payload)
            except vol.Invalid:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Invalid authorization code"
                    },
                    status_code=400)

            code = self.auth_manager.auth_codes.get(payload["code"])
            if not code:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Invalid authorization code"
                    },
                    status_code=400)

            if code.expired:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Authorization code expired"
                    },
                    status_code=400)

            self.auth_manager.remove_authorization_code(code)

            refresh_token = await self.auth_manager.create_refresh_token(
                client_id=cast(str, code.client_id),
                access_token_expiration=code.access_token_expiration,
                user=code.user)

        elif payload["grant_type"] == "password":
            try:
                payload = PASSWORD_SCHEMA(payload)
            except vol.Invalid:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Invalid credentials"
                    },
                    status_code=400)

            cred_provider: "CredentialProvider" = (
                self.auth_manager.credential_providers["password"])

            user = self.auth_manager.get_user_by_name(payload["username"])

            login_valid = await cred_provider.validate_login_data(
                user, payload["password"]) if user else False

            if not login_valid:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Invalid credentials"
                    },
                    status_code=400)

            refresh_token = await self.auth_manager.create_refresh_token(
                payload["client_id"], user=user)

        elif payload["grant_type"] == "refresh_token":
            try:
                payload = REFRESH_TOKEN_SCHEMA(payload)
            except vol.Invalid as e:
                if "refresh_token" in e.path:
                    return self.json(
                        {
                            "error":
                            "invalid_grant",
                            "error_description":
                            "Grant type 'refresh_token'"
                            "needs a 'refresh_token'"
                            "parameter"
                        },
                        status_code=400)

                invalid = ', '.join(e.path)
                return self.json(
                    {
                        "error": "invalid_request",
                        "error_description": f"Invalid parameters: {invalid}"
                    },
                    status_code=400)

            refresh_token = self.auth_manager.get_refresh_token_by_string(
                payload["refresh_token"])

            if not refresh_token:
                return self.json(
                    {
                        "error": "invalid_grant",
                        "error_description": "Invalid refresh token"
                    },
                    status_code=400)

        else:
            return self.json({
                "error":
                "invalid_grant",
                "error_description":
                "The given grant type is not supported "
            })

        access_token = await self.auth_manager.create_access_token(
            refresh_token)

        return JSONResponse(
            {
                "access_token": access_token.token,
                "token_type": "bearer",
                "expires_in": access_token.expiration,
                "refresh_token": refresh_token.token,
            },
            headers={hdrs.CACHE_CONTROL: "no-store"})
예제 #23
0
파일: module.py 프로젝트: zuurw/HomeControl
        async def get_event_log(request: web.Request) -> JSONResponse:
            with self.session_context() as session:
                result = session.query(models.EventLog)

            return JSONResponse(result.all())
예제 #24
0
 async def shutdown(request: web.Request) -> JSONResponse:
     """Handle /core/shutdown"""
     self.core.loop.call_soon(self.core.shutdown)
     return JSONResponse("Shutting down")
예제 #25
0
 async def get_login_flow_providers(
         request: web.Request) -> JSONResponse:
     """Returns a list of login providers"""
     return JSONResponse(list(self.flow_manager.flow_factories.keys()))
예제 #26
0
 async def restart(request: web.Request) -> JSONResponse:
     self.core.loop.call_soon(self.core.restart)
     return JSONResponse("Restarting")
예제 #27
0
 async def reload_config(request: web.Request) -> JSONResponse:
     await self.core.cfg.reload_config()
     return JSONResponse("Reloaded configuration")