コード例 #1
0
    def _validate_webpush(self, d, result):
        db = self.context["db"]  # type: DatabaseManager
        log = self.context["log"]  # type: Logger
        channel_id = normalize_id(d["chid"])
        uaid = result["uaid"]
        if 'current_month' not in result:
            log.info(format="Dropping User",
                     code=102,
                     uaid_hash=hasher(uaid),
                     uaid_record=dump_uaid(result))
            db.router.drop_user(uaid)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)

        month_table = result["current_month"]
        if month_table not in db.message_tables:
            log.info(format="Dropping User",
                     code=103,
                     uaid_hash=hasher(uaid),
                     uaid_record=dump_uaid(result))
            db.router.drop_user(uaid)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)
        exists, chans = db.message_tables[month_table].all_channels(uaid=uaid)

        if (not exists or channel_id.lower() not in map(
                lambda x: normalize_id(x), chans)):
            log.info("Unknown subscription: {channel_id}",
                     channel_id=channel_id)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)
コード例 #2
0
ファイル: test_db.py プロジェクト: lholmquist/autopush
    def test_hasher(self):
        import autopush.db as db

        db.key_hash = "SuperSikkret"
        v = db.hasher("01234567123401234123456789ABCDEF")
        eq_(v, "0530bb351921e7b4be66831e4c126c6" + "d8f614d06cdd592cb8470f31177c8331a")
        db.key_hash = ""
コード例 #3
0
ファイル: test_web_base.py プロジェクト: adamchainz/autopush
 def test_properties(self):
     eq_(self.base.uaid, "")
     eq_(self.base.chid, "")
     self.base.uaid = dummy_uaid
     eq_(self.base._client_info["uaid_hash"], hasher(dummy_uaid))
     self.base.chid = dummy_chid
     eq_(self.base._client_info['channelID'], dummy_chid)
コード例 #4
0
ファイル: test_web_base.py プロジェクト: adamchainz/autopush
 def test_properties(self):
     eq_(self.base.uaid, "")
     eq_(self.base.chid, "")
     self.base.uaid = dummy_uaid
     eq_(self.base._client_info["uaid_hash"], hasher(dummy_uaid))
     self.base.chid = dummy_chid
     eq_(self.base._client_info['channelID'], dummy_chid)
コード例 #5
0
 def _write_endpoint(self,
                     endpoint,
                     uaid,
                     chid,
                     router_type,
                     router_data,
                     new_uaid=False):
     # type: (str, uuid.UUID, str, str, JSONDict, bool) -> None
     """Write the JSON response of the created endpoint"""
     response = dict(channelID=chid, endpoint=endpoint)
     if new_uaid:
         secret = None
         if self.conf.bear_hash_key:
             secret = generate_hash(self.conf.bear_hash_key[0], uaid.hex)
         response.update(uaid=uaid.hex, secret=secret)
         # Apply any router specific fixes to the outbound response.
         router = self.routers[router_type]
         router.amend_endpoint_response(response, router_data)
     self.set_header("Content-Type", "application/json")
     self.write(json.dumps(response))
     self.log.info("Register",
                   client_info=self._client_info,
                   endpoint=endpoint,
                   uaid_hash=hasher(uaid.hex))
     self.finish()
コード例 #6
0
ファイル: webpush.py プロジェクト: DejunLiu/autopush
    def post(self, *args, **kwargs):
        # Store Vapid info if present
        jwt = self.valid_input.get("jwt")
        if jwt:
            self._client_info["jwt_crypto_key"] = jwt["jwt_crypto_key"]
            for i in jwt["jwt_data"]:
                self._client_info["jwt_" + i] = jwt["jwt_data"][i]

        user_data = self.valid_input["subscription"]["user_data"]
        router = self.ap_settings.routers[user_data["router_type"]]
        notification = self.valid_input["notification"]
        self._client_info["message_id"] = notification.message_id
        self._client_info["uaid"] = hasher(user_data.get("uaid"))
        self._client_info["channel_id"] = user_data.get("chid")
        self._client_info["router_key"] = user_data["router_type"]
        self._client_info["message_size"] = len(notification.data or "")
        self._client_info["ttl"] = notification.ttl
        self._client_info["version"] = notification.version
        self._router_time = time.time()
        d = Deferred()
        d.addCallback(router.route_notification, user_data)
        d.addCallback(self._router_completed, user_data, "")
        d.addErrback(self._router_fail_err)
        d.addErrback(self._response_err)

        # Call the prepared router
        d.callback(notification)
コード例 #7
0
    def process(self, command):
        # type: (Register) -> Union[RegisterResponse, RegisterErrorResponse]
        valid, msg = _validate_chid(command.channel_id)
        if not valid:
            return RegisterErrorResponse(error_msg=msg)

        endpoint = self.conf.make_endpoint(
            command.uaid.hex,
            command.channel_id,
            command.key
        )
        message = self.db.message_tables[command.message_month]
        try:
            message.register_channel(command.uaid.hex, command.channel_id)
        except ClientError as ex:
            if (ex.response['Error']['Code'] ==
                    "ProvisionedThroughputExceededException"):
                return RegisterErrorResponse(error_msg="overloaded",
                                             status=503)

        self.metrics.increment('ua.command.register')
        log.info(
            "Register",
            channel_id=command.channel_id,
            endpoint=endpoint,
            uaid_hash=hasher(command.uaid.hex),
        )
        return RegisterResponse(endpoint=endpoint)
コード例 #8
0
ファイル: registration.py プロジェクト: mendrugory/autopush
 def _delete_channel(self, uaid, chid):
     if not self.db.message.unregister_channel(uaid.hex, chid):
         raise ItemNotFound("ChannelID not found")
     self.log.info("Unregister",
                   client_info=self._client_info,
                   channel_id=chid,
                   uaid_hash=hasher(uaid))
コード例 #9
0
ファイル: test_db.py プロジェクト: Acidburn0zzz/autopush
 def test_hasher(self):
     import autopush.db as db
     db.key_hash = "SuperSikkret"
     v = db.hasher("01234567123401234123456789ABCDEF")
     assert v == ('0530bb351921e7b4be66831e4c126c6'
                  'd8f614d06cdd592cb8470f31177c8331a')
     db.key_hash = ""
コード例 #10
0
ファイル: webpush.py プロジェクト: mendrugory/autopush
    def _router_completed(self,
                          response,
                          uaid_data,
                          warning="",
                          router_type=None,
                          vapid=None):
        """Called after router has completed successfully"""
        # Log the time taken for routing
        self._timings["route_time"] = time.time() - self._router_time
        # Were we told to update the router data?
        time_diff = time.time() - self._start_time
        if response.router_data is not None:
            if not response.router_data:
                # An empty router_data object indicates that the record should
                # be deleted. There is no longer valid route information for
                # this record.
                self.log.debug(format="Dropping User",
                               code=100,
                               uaid_hash=hasher(uaid_data["uaid"]),
                               uaid_record=dump_uaid(uaid_data),
                               client_info=self._client_info)
                d = deferToThread(self.db.router.drop_user, uaid_data["uaid"])
                d.addCallback(lambda x: self._router_response(response))
                return d
            # The router data needs to be updated to include any changes
            # requested by the bridge system
            uaid_data["router_data"] = response.router_data
            # set the AWS mandatory data
            uaid_data["connected_at"] = ms_time()
            d = deferToThread(self.db.router.register_user, uaid_data)
            response.router_data = None
            d.addCallback(lambda x: self._router_completed(
                response, uaid_data, warning, router_type, vapid))
            return d
        else:
            # No changes are requested by the bridge system, proceed as normal
            dest = 'Direct'
            if response.status_code == 200 or response.logged_status == 200:
                self.log.debug(format="Successful delivery",
                               client_info=self._client_info)
            elif response.status_code == 202 or response.logged_status == 202:
                self.log.debug(format="Router miss, message stored.",
                               client_info=self._client_info)
                dest = 'Stored'
            self.metrics.timing("notification.request_time",
                                duration=time_diff)
            self.metrics.increment('notification.message.success',
                                   tags=make_tags(destination=dest,
                                                  router=router_type,
                                                  vapid=(vapid is not None)))

            response.response_body = (response.response_body + " " +
                                      warning).strip()
            self._router_response(response)
コード例 #11
0
 def drop_user(self, uaid, uaid_record, code):
     # type: (str, dict, int) -> None
     """Drop a user record"""
     log.debug(
         "Dropping User",
         code=code,
         uaid_hash=hasher(uaid),
         uaid_record=repr(uaid_record)
     )
     self.metrics.increment('ua.expiration', tags=['code:{}'.format(code)])
     self.db.router.drop_user(uaid)
コード例 #12
0
ファイル: webpush.py プロジェクト: anandrmedia/autopush
    def validate_uaid_month_and_chid(self, d):
        db = self.context["db"]  # type: DatabaseManager

        try:
            result = db.router.get_uaid(d["uaid"].hex)
        except ItemNotFound:
            raise InvalidRequest("UAID not found", status_code=410, errno=103)

        # We must have a router_type to validate the user
        router_type = result.get("router_type")
        if router_type not in VALID_ROUTER_TYPES:
            self.context["log"].debug(format="Dropping User",
                                      code=102,
                                      uaid_hash=hasher(result["uaid"]),
                                      uaid_record=repr(result))
            self.context["metrics"].increment("updates.drop_user",
                                              tags=make_tags(errno=102))
            self.context["db"].router.drop_user(result["uaid"])
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)

        if (router_type == "gcm" and 'senderID' not in result.get(
                'router_data', {}).get("creds", {})):
            # Make sure we note that this record is bad.
            result['critical_failure'] = \
                result.get('critical_failure', "Missing SenderID")
            db.router.register_user(result)

        if (router_type == "fcm"
                and 'app_id' not in result.get('router_data', {})):
            # Make sure we note that this record is bad.
            result['critical_failure'] = \
                result.get('critical_failure', "Missing SenderID")
            db.router.register_user(result)

        if result.get("critical_failure"):
            raise InvalidRequest("Critical Failure: %s" %
                                 result.get("critical_failure"),
                                 status_code=410,
                                 errno=105)
        # Some stored user records are marked as "simplepush".
        # If you encounter one, may need to tweak it a bit to get it as
        # a valid WebPush record.
        if result["router_type"] == "simplepush":
            result["router_type"] = "webpush"

        if result["router_type"] == "webpush":
            self._validate_webpush(d, result)

        # Propagate the looked up user data back out
        d["user_data"] = result
コード例 #13
0
ファイル: webpush.py プロジェクト: saurabharch/autopush
    def _validate_webpush(self, d, result):
        db = self.context["db"]  # type: DatabaseManager
        log = self.context["log"]  # type: Logger
        metrics = self.context["metrics"]  # type: IMetrics
        channel_id = normalize_id(d["chid"])
        uaid = result["uaid"]
        if 'current_month' not in result:
            log.debug(format="Dropping User",
                      code=102,
                      uaid_hash=hasher(uaid),
                      uaid_record=repr(result))
            metrics.increment("updates.drop_user", tags=make_tags(errno=102))
            db.router.drop_user(uaid)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)

        month_table = result["current_month"]
        if month_table not in db.message_tables:
            log.debug(format="Dropping User",
                      code=103,
                      uaid_hash=hasher(uaid),
                      uaid_record=repr(result))
            metrics.increment("updates.drop_user", tags=make_tags(errno=103))
            db.router.drop_user(uaid)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)
        msg = db.message_table(month_table)
        exists, chans = msg.all_channels(uaid=uaid)

        if (not exists or channel_id.lower() not in map(
                lambda x: normalize_id(x), chans)):
            log.debug("Unknown subscription: {channel_id}",
                      channel_id=channel_id)
            raise InvalidRequest("No such subscription",
                                 status_code=410,
                                 errno=106)
コード例 #14
0
ファイル: webpush.py プロジェクト: saurabharch/autopush
    def post(
            self,
            subscription,  # type: Dict[str, Any]
            notification,  # type: WebPushNotification
            jwt=None,  # type: Optional[JSONDict]
            **kwargs  # type: Any
    ):
        # type: (...) -> Deferred
        # Store Vapid info if present
        if jwt:
            self.metrics.increment("updates.vapid.{}".format(
                kwargs.get('vapid_version')))
            self._client_info["jwt_crypto_key"] = jwt["jwt_crypto_key"]
            for i in jwt["jwt_data"]:
                self._client_info["jwt_" + i] = jwt["jwt_data"][i]

        user_data = subscription["user_data"]
        encoding = ''
        if notification.data and notification.headers:
            encoding = notification.headers.get('encoding', '')
            self.metrics.increment(
                "updates.notification.encoding.{}".format(encoding))
        self._client_info.update(
            message_id=notification.message_id,
            uaid_hash=hasher(user_data.get("uaid")),
            channel_id=notification.channel_id.hex,
            router_key=user_data["router_type"],
            message_size=notification.data_length,
            message_ttl=notification.ttl,
            version=notification.version,
            encoding=encoding,
        )
        router_type = user_data["router_type"]
        router = self.routers[router_type]
        self._router_time = time.time()
        d = maybeDeferred(router.route_notification, notification, user_data)
        d.addCallback(self._router_completed,
                      user_data,
                      "",
                      router_type=router_type,
                      vapid=jwt)
        d.addErrback(self._router_fail_err,
                     router_type=router_type,
                     vapid=jwt is not None,
                     uaid=user_data.get("uaid"))
        d.addErrback(self._response_err)
        return d
コード例 #15
0
ファイル: websocket.py プロジェクト: marco-c/autopush
    def process_hello(self, data):
        """Process a hello message"""
        # This must be a helo, or we kick the client
        cmd = data.get("messageType")
        if cmd != "hello":
            return self.sendClose()

        if self.ps.uaid:
            return self.returnError("hello", "duplicate hello", 401)

        uaid = data.get("uaid")
        self.ps.use_webpush = data.get("use_webpush", False)
        self.ps._base_tags.append("use_webpush:%s" %
                                  self.ps.use_webpush)
        self.ps.router_type = "webpush" if self.ps.use_webpush\
                              else "simplepush"
        if self.ps.use_webpush:
            self.ps.updates_sent = defaultdict(lambda: [])
            self.ps.direct_updates = defaultdict(lambda: [])

        existing_user, uaid = validate_uaid(uaid)
        self.ps.uaid = uaid
        self.ps.uaid_hash = hasher(uaid)
        # Check for the special wakeup commands
        if "wakeup_host" in data and "mobilenetwork" in data:
            wakeup_host = data.get("wakeup_host")
            if "ip" in wakeup_host and "port" in wakeup_host:
                mobilenetwork = data.get("mobilenetwork")
                # Normalize the wake info to a single object.
                wake_data = dict(data=dict(ip=wakeup_host["ip"],
                                 port=wakeup_host["port"],
                                 mcc=mobilenetwork.get("mcc", ''),
                                 mnc=mobilenetwork.get("mnc", ''),
                                 netid=mobilenetwork.get("netid", '')))
                self.ps.wake_data = wake_data

        self.transport.pauseProducing()

        d = self._register_user(existing_user)
        d.addCallback(self._copy_new_data)
        d.addCallback(self._check_collision)
        d.addErrback(self.trap_cancel)
        d.addErrback(self.err_overload, "hello")
        d.addErrback(self.err_hello)
        self.ps._register = d
        return d
コード例 #16
0
    def process_hello(self, data):
        """Process a hello message"""
        # This must be a helo, or we kick the client
        cmd = data.get("messageType")
        if cmd != "hello":
            return self.sendClose()

        if self.ps.uaid:
            return self.returnError("hello", "duplicate hello", 401)

        uaid = data.get("uaid")
        self.ps.use_webpush = data.get("use_webpush", False)
        self.ps._base_tags.append("use_webpush:%s" % self.ps.use_webpush)
        self.ps.router_type = "webpush" if self.ps.use_webpush\
                              else "simplepush"
        if self.ps.use_webpush:
            self.ps.updates_sent = defaultdict(lambda: [])
            self.ps.direct_updates = defaultdict(lambda: [])

        existing_user, uaid = validate_uaid(uaid)
        self.ps.uaid = uaid
        self.ps.uaid_hash = hasher(uaid)
        # Check for the special wakeup commands
        if "wakeup_host" in data and "mobilenetwork" in data:
            wakeup_host = data.get("wakeup_host")
            if "ip" in wakeup_host and "port" in wakeup_host:
                mobilenetwork = data.get("mobilenetwork")
                # Normalize the wake info to a single object.
                wake_data = dict(
                    data=dict(ip=wakeup_host["ip"],
                              port=wakeup_host["port"],
                              mcc=mobilenetwork.get("mcc", ''),
                              mnc=mobilenetwork.get("mnc", ''),
                              netid=mobilenetwork.get("netid", '')))
                self.ps.wake_data = wake_data

        self.transport.pauseProducing()

        d = self._register_user(existing_user)
        d.addCallback(self._copy_new_data)
        d.addCallback(self._check_collision)
        d.addErrback(self.trap_cancel)
        d.addErrback(self.err_overload, "hello")
        d.addErrback(self.err_hello)
        self.ps._register = d
        return d
コード例 #17
0
    def put(self, subscription, version, data):
        # type: (Dict[str, Any], str, str) -> Deferred
        user_data = subscription["user_data"]
        self._client_info.update(uaid_hash=hasher(user_data.get("uaid")),
                                 channel_id=user_data.get("chid"),
                                 message_id=str(version),
                                 router_key=user_data["router_type"])
        notification = Notification(
            version=version,
            data=data,
            channel_id=str(subscription["chid"]),
        )

        router = self.routers[user_data["router_type"]]
        d = maybeDeferred(router.route_notification, notification, user_data)
        d.addCallback(self._router_completed, user_data, "")
        d.addErrback(self._router_fail_err)
        d.addErrback(self._response_err)
        return d
コード例 #18
0
    def put(self, *args, **kwargs):
        sub = self.valid_input["subscription"]
        user_data = sub["user_data"]
        router = self.ap_settings.routers[user_data["router_type"]]
        self._client_info["uaid"] = hasher(user_data.get("uaid"))
        self._client_info["channel_id"] = user_data.get("chid")
        self._client_info["message_id"] = self.valid_input["version"]
        self._client_info["router_key"] = user_data["router_type"]

        notification = Notification(
            version=self.valid_input["version"],
            data=self.valid_input["data"],
            channel_id=str(sub["chid"]),
        )

        d = Deferred()
        d.addCallback(router.route_notification, user_data)
        d.addCallback(self._router_completed, user_data, "")
        d.addErrback(self._router_fail_err)
        d.addErrback(self._response_err)

        # Call the prepared router
        d.callback(notification)
コード例 #19
0
    def process(self,
                command  # type: Unregister
                ):
        # type: (...) -> Union[UnregisterResponse, UnregisterErrorResponse]
        valid, msg = _validate_chid(command.channel_id)
        if not valid:
            return UnregisterErrorResponse(error_msg=msg)

        message = self.db.message_tables[command.message_month]
        # TODO: JSONResponseError not handled (no force_retry)
        message.unregister_channel(command.uaid.hex, command.channel_id)

        # TODO: Clear out any existing tracked messages for this
        # channel

        self.metrics.increment('ua.command.unregister')
        # TODO: user/raw_agent?
        log.info(
            "Unregister",
            channel_id=command.channel_id,
            uaid_hash=hasher(command.uaid.hex),
            **dict(code=command.code) if command.code else {}
        )
        return UnregisterResponse()
コード例 #20
0
ファイル: endpoint.py プロジェクト: marco-c/autopush
 def uaid(self, value):
     """Set the UAID and update the uaid hash"""
     self._uaid = value
     self.uaid_hash = hasher(value)
     self._client_info["uaid_hash"] = self.uaid_hash
コード例 #21
0
ファイル: endpoint.py プロジェクト: oremj/autopush
 def uaid(self, value):
     """Set the UAID and update the uaid hash"""
     self._uaid = value
     self.uaid_hash = hasher(value)
     self._client_info["uaid_hash"] = self.uaid_hash
コード例 #22
0
 def _delete_uaid(self, uaid):
     self.log.debug(format="Dropping User",
                    code=101,
                    uaid_hash=hasher(uaid.hex))
     if not self.db.router.drop_user(uaid.hex):
         raise ItemNotFound("UAID not found")