Exemplo n.º 1
0
    def client_ids_by_owner(self, owner):
        """
        Parameters
        ----------
        owner : str
            Username of the owner of the client application.

        Returns
        -------
        list of str
            A list of client's ID owned by the user.

        """
        url = Client.base_URL + 'apps/by-owner'
        param = {'owner': owner}
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        response = self._check_token(response=requests.get(url, headers=header, params=param),
                                     flag='GET', url=url, params=param)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            else:
                raise InternalError()
        clientObject = response.json()
        clientIDs = []
        for ct in clientObject:
            clientIDs.append(ct['clientID'])
        return clientIDs
Exemplo n.º 2
0
    def camera_by_id(self, cameraID):
        """
        A method to get a camera object by using camera's ID

        Parameters
        ----------
        cameraID : str
            Id of the camera in the database.

        Returns
        -------
        :obj:`Camera`
            A camera object.

        """
        if self.token is None:
            self._request_token()
        url = Client.base_URL + "cameras/" + cameraID
        header = self.header_builder()
        response = self._check_token(response=requests.get(url, headers=header),
                                     flag='GET', url=url)

        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 404:
                raise ResourceNotFoundError(response.json()['message'])
            elif response.status_code == 403:
                raise AuthorizationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            else:
                raise InternalError()
        return Camera.process_json(**response.json())
Exemplo n.º 3
0
    def usage_by_client(self, clientID, owner):
        """
        Parameters
        ----------
        clientID : str
            Client's ID of the application.

        owner : str
            Username of the owner of the client application.

        Returns
        -------
        int
            The number of requests made by the client.

        """
        url = Client.base_URL + "apps/" + clientID + "/usage"
        param = {'owner': owner}
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        response = self._check_token(response=requests.get(url, headers=header, params=param),
                                     flag='GET', url=url, params=param)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 403:
                raise AuthorizationError(response.json()['message'])
            elif response.status_code == 404:
                raise ResourceNotFoundError(response.json()['message'])
            else:
                raise InternalError()
        return response.json()['api_usage']
Exemplo n.º 4
0
    def reset_secret(self, clientID):
        """
        Parameters
        ----------

        clientID: str
            Client Id of the application.

        Returns
        --------
        str
            New clientSecret

        """
        url = Client.base_URL + 'apps/' + clientID + '/secret'
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        response = self._check_token(response=requests.put(url, headers=header, data=None),
                                     flag='PUT', url=url, data=None)

        if response.status_code != 200:

            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])

            elif response.status_code == 404:
                raise ResourceNotFoundError(response.json()['message'])

            else:
                raise InternalError()

        return response.json()['clientSecret']
Exemplo n.º 5
0
    def update_permission(self, clientID, permissionLevel):
        """
        Parameters
        ----------
        clientID : str
            Client Id of the application.

        permissionLevel : str, optional
            Permission level of client.

        Returns
        -------
        str
            Success message.

        """
        url = Client.base_URL + 'apps/' + clientID
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        data = {'permissionLevel': permissionLevel}
        response = self._check_token(response=requests.put(url, headers=header, data=data),
                                     flag='PUT', url=url, data=data)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 404:
                raise ResourceNotFoundError(response.json()['message'])
            else:
                raise InternalError()
        return response.json()['message']
Exemplo n.º 6
0
    def register(self, owner, permissionLevel='user'):
        """Client initialization method.

        Parameters
        ----------
        owner : str
            Username of the owner of the client application.
        permissionLevel : str, optional
            Permission level of the owner of the client application.
            Default permission level is 'user'.


        Returns
        -------
        str
            Client id of the newly registered client application.
        str
            Client secret of the newly registered client application.

        """
        url = Client.base_URL + 'apps/register'
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        data = {'owner': owner, 'permissionLevel': permissionLevel}
        response = self._check_token(response=requests.post(url, headers=header, data=data),
                                     flag='POST', url=url, data=data)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            else:
                raise InternalError()
        return response.json()['clientID'], response.json()['clientSecret']
Exemplo n.º 7
0
 def _resp_handle(self, uri, resp, decode=True):
     kwargs = {
         "uri": uri,
         "status_code": resp.status_code,
         "message": resp.text
     }
     if resp.status_code >= 500:
         raise ServerError(**kwargs)
     elif resp.status_code == 401:
         raise AuthenticationError(**kwargs)
     elif resp.status_code == 423:
         raise ServerIsBeingUpdatedError(**kwargs)
     elif resp.status_code == 400:
         try:
             kwargs["message"] = resp.json().get("messages", "")
         except Exception:
             pass
         raise BadRequestError(**kwargs)
     elif resp.status_code != 200:
         raise ClientError(**kwargs)
     if decode:
         try:
             return resp.json()
         except Exception:
             raise BadResponseError(**kwargs)
     return resp.content
Exemplo n.º 8
0
def handle_api_error(msg, status_code):
    if status_code == 400:
        raise InvalidRequestError(msg, status_code)
    elif status_code == 401:
        raise AuthenticationError(msg, status_code)
    elif status_code == 500:
        raise InternalServerError(msg, status_code)
    else:
        raise XfersError(msg, status_code)
Exemplo n.º 9
0
    def get_change_log(self, start=None, end=None, offset=None):
        """
        Parameters
        ----------
        start : str, optional
            Start time of the log user desires to query
        end : str, optional
            End time of the log user desires to query
        offset : str, optional
            How many logs to skip

        Returns
        -------
        list of dict of {str : str}
            A list of objects containing cameraID and creation time of the log.

        Raises
        ------
        AuthenticationError
            If the client secret of this client object does not match the clientID.
        InternalError
            If there is an API internal error.
        FormatError
            If type of argument value is not expected for the given field.

        """
        url = Client.base_URL + 'apps/db-change'
        if self.token is None:
            self._request_token()
        header = self.header_builder()
        param = {'start': start,
                 'end': end,
                 'offset': offset}
        response = self._check_token(response=requests.get(url, headers=header, params=param),
                                     flag='GET', url=url, params=param)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            else:
                raise InternalError()

        return response.json()
Exemplo n.º 10
0
    def _request_token(self):

        """A method to request an access token for the client application.
        Raises
        ------
        ResourceNotFoundError
            If no client app exists with the clientID of this client object.
        AuthenticationError
            If the client secret of this client object does not match the clientID.
        InternalError
            If there is an API internal error.
        """

        url = self.base_URL + 'auth'
        param = {'clientID': self.clientID, 'clientSecret': self.clientSecret}
        response = requests.get(url, params=param)
        if response.status_code == 200:
            self.token = response.json()['token']
        elif response.status_code == 404:
            raise ResourceNotFoundError(response.json()['message'])
        elif response.status_code == 401:
            raise AuthenticationError(response.json()['message'])
        else:
            raise InternalError()
Exemplo n.º 11
0
def login(params):
    """Login to the server and get session token"""

    if not params.auth_verifier:
        if params.debug:
            print('No auth verifier, sending pre-auth request')

        payload = {
            'command': 'login',
            'include': ['keys'],
            'version': 2,
            'client_version': CLIENT_VERSION,
            'username': params.email
        }

        try:
            r = requests.post(params.server, json=payload)
        except:
            print('Comm error during login')
            raise CommunicationError(sys.exc_info()[0])

        if params.debug:
            debug_response(params, payload, r)

        if not 'salt' in r.json():
            if r.json()['result_code'] == 'Failed_to_find_user':
                raise AuthenticationError('User account [' + \
                    str(params.email) + '] not found.')

            if r.json()['result_code'] == 'auth_failed':
                raise AuthenticationError('Pre-auth failed.')

        # server doesn't include == at the end, but the module expects it
        params.salt = base64.urlsafe_b64decode(r.json()['salt'] + '==')
        params.iterations = r.json()['iterations']

        prf = lambda p, s: HMAC.new(p, s, SHA256).digest()
        tmp_auth_verifier = base64.urlsafe_b64encode(
            PBKDF2(params.password, params.salt, 32, params.iterations, prf))

        # converts bytestream (b') to string
        params.auth_verifier = tmp_auth_verifier.decode()

        if params.debug:
            print('<<< Auth Verifier:[' + str(params.auth_verifier) + ']')

    success = False
    while not success:

        if params.mfa_token:
            payload = {
                'command': 'login',
                'include': ['keys'],
                'version': 2,
                'auth_response': params.auth_verifier,
                'client_version': CLIENT_VERSION,
                '2fa_token': params.mfa_token,
                '2fa_type': params.mfa_type,
                'username': params.email
            }

        else:
            payload = {
                'command': 'login',
                'include': ['keys'],
                'version': 2,
                'auth_response': params.auth_verifier,
                'client_version': CLIENT_VERSION,
                'username': params.email
            }

        try:
            r = requests.post(params.server, json=payload)
        except:
            raise CommunicationError(sys.exc_info()[0])

        response_json = r.json()

        if params.debug:
            debug_response(params, payload, r)

        if (response_json['result_code'] == 'auth_success'
                and response_json['result'] == 'success'):
            if params.debug: print('Auth Success')

            if 'session_token' in response_json:
                params.session_token = response_json['session_token']

            if 'device_token' in response_json:
                params.mfa_token = response_json['device_token']
                # save token to config file
                params.config['mfa_type'] = 'device_token'
                params.config['mfa_token'] = params.mfa_token
                try:
                    with open(params.config_filename, 'w') as f:
                        json.dump(params.config, f, ensure_ascii=False)
                        print('Updated mfa_token in ' + params.config_filename)
                except:
                    print('Unable to update mfa_token')

            if params.mfa_token:
                params.mfa_type = 'device_token'
            else:
                params.mfa_type = ''

            if 'keys' in response_json:
                if 'encrypted_private_key' in response_json['keys']:
                    params.encrypted_private_key = \
                        response_json['keys']['encrypted_private_key']
                else:
                    raise CommunicationError('Encrypted private ' + \
                      'key not found. You are probably using the wrong server.')

                if 'encryption_params' in response_json['keys']:
                    params.encryption_params = \
                        response_json['keys']['encryption_params']
                else:
                    print('Encryption parameters not found.')

                decrypt_data_key(params)
                decrypt_private_key(params)

            else:
                print('Hmm... keys not provided in login response.')

            success = True

        elif (response_json['result_code'] == 'need_totp'
              or response_json['result_code'] == 'invalid_device_token'
              or response_json['result_code'] == 'invalid_totp'):
            try:
                params.mfa_token = ''
                params.mfa_type = 'one_time'

                while not params.mfa_token:
                    try:
                        params.mfa_token = getpass.getpass(
                            prompt='Two-Factor Code: ', stream=None)
                    except (KeyboardInterrupt):
                        print('Cancelled')
                        raise

            except (EOFError, KeyboardInterrupt, SystemExit):
                return

        elif response_json['result_code'] == 'auth_failed':
            raise AuthenticationError('Authentication failed.')

        elif response_json['result_code'] == 'throttled':
            raise AuthenticationError(response_json['message'])

        elif response_json['result_code']:
            raise AuthenticationError(response_json['result_code'])

        else:
            raise CommunicationError('Unknown problem')
Exemplo n.º 12
0
 def authenticate(self, username):
     response, content = self._request(urljoin(
         self.connection.host, '/become?user_name=' + username),
                                       method='GET')
     if response.status != 302:
         raise AuthenticationError(content)
Exemplo n.º 13
0
 def authenticate(self, username, password):
     data = self._call('authenticate', username, password)
     if not data['success']:
         raise AuthenticationError()
Exemplo n.º 14
0
    def check_cam_exist(self, camera_type, **kwargs):
        """
        A method to get one or more camera object that has the given retrieval method
        in the database.

        Parameters
        ----------
        camera_type : str
            Type of the camera. Type can only be 'ip', 'non_ip', or 'stream'.
        ip : str, optional
            [for IP camera] Ip address of the camera. Although marked as optional,
            this field is required when the camera type is 'ip'.
        port : Int, optional
            [for IP camera] Port of the camera. If no port provided, it will be set to default 80.
        image_path : str, optional
            [for IP camera] Path to retrieve images from the camera.
        video_path : str, optinal
            [for IP camera] Path to retrievae vidoe from the camera.
        snapshot_url : str, optional
            [for non_IP camera] Url to retrieval image frames from the camera.
            Although marked as optional, this field is required when the camera type is 'non_ip'.
        m3u8_url : str, optional
            [for stream camera] Url to retrieval video stream from the camera.
            Although marked as optional, this field is required when the camera type is 'stream'.

        Returns
        -------
        :obj:`list` of :obj:`Camera`
            List of camera objects that has the given retrieval method. If there are no cameras
            matches the provided retrieval information, an empty list will be returned.

        Raises
        ------
        FormatError
            If camera type is not valid.

            Or camera type is not provided.

            Or ip is not provided when the camera type is 'ip'.

            Or snapshot_url is not provided when the camera type is 'non_ip'.

            Or m3u8_url is not provided when the camera ytpe is 'stream'.

            Or there are unexpected keywords in kwargs.

        AuthenticationError
            If the client secret of this client object does not match the clientID.
        ResourceNotFoundError
            If the client id of this client object does not match any client
            in the database.
        InternalError
            If there is an API internal error.
        """

        self._check_args(kwargs, self._retrieval_fields)

        url = Client.base_URL + "cameras/exist"
        kwargs['type'] = camera_type

        if self.token is None:
            self._request_token()
        header = self.header_builder()
        response = self._check_token(response=requests.get(url, headers=header, params=kwargs),
                                     flag='GET', url=url, params=kwargs)
        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            else:
                raise InternalError()
        camera_response_array = response.json()
        camera_processed = []
        for current_object in camera_response_array:
            camera_processed.append(Camera.process_json(**current_object))
        return camera_processed
Exemplo n.º 15
0
    def search_camera(self, **kwargs):

        """A method to search camera by attributes and location.
        Searching by location requires user to provide coordiantes for a desired center point
        and a radius in meters. The search will carry out in the area bounded by the circle.
        Each time, this function can return a maximum of 100 cameras. Getting more cameras can
        be achieved by calling this function multiple times with offest parameter.

        Parameters
        ----------

        latitude : float, optional
            Latitude of the center of the circle area to be searched.
            Latitude ranges between +90 and -90.

            NOTE: please specify longitude and radius if this parameter value is provided.
        longitude : float, optional
            Longitude of the center of the circle area to be searched.
            Longitude ranges between +180 and -180.

            NOTE: please specify latitude and radius if this parameter value is provided.
        radius : float, optional
            Radius in km of the circle area to be searched. Radius should be positive

            NOTE: please specify latitude and longitude if this parameter value is provided.
        offset : int, optional
            Number of cameras skipped. Since each time this function can return max 100 cameras,
            calling this function the second time adding `offset=100` will get the second 100
            cameras beyond the first list of 100 cameras.
        camera_type : str, optional
            Type of camera.
            Allowed values: 'ip', 'non_ip', 'stream'.
        source : str, optional
            Source of the camera.
        country : str, optional
            Country which the camera locates at.
        state : str, optional
            State which the camera locates at.
        city : str, optional
            City which the camera locates at.
        resolution_width : int, optional
            Resolution width of the camera. It has to be positive.
        resolution_height : int, optional
            Resolution height of the camera. It has to be positive.
        is_active_image : bool, optional
            If the camera is active and can get images.
            This field can identify true/false case-insensitively and 0/1.
        is_active_video : bool, optional
            If the camera is active and can get video.
            This field can identify true/false case-insensitively and 0/1.

        Returns
        -------
        :obj:`list` of :obj:`Camera`
            List of cameras that satisfy the search criteria.

        Raises
        ------
        FormatError

            If type of argument value is not expected for the given field.

            Or there are unexpected keywords in kwargs.

            Or radius cannot is less than 0.

            Or incorrect latitude range. (it should be between +90 and -90)

            Or incorrect longitude range. (it should be between +180 and -180)

        AuthenticationError
            If the client secret of this client object does not match the clientID.
        ResourceNotFoundError
            If the client id of this client object does not match any client
            in the database.
        InternalError
            If there is an API internal error.

        """
        if self.token is None:
            self._request_token()

        self._check_args(kwargs, self._search_fields)

        kwargs['type'] = kwargs.pop('camera_type', None)

        # filter out those parameters with value None, change true/false
        search_params = {k: v for k, v in kwargs.items() if v is not None}

        url = Client.base_URL + 'cameras/search'
        header = self.header_builder()
        response = self._check_token(
            response=requests.get(url, headers=header, params=search_params),
            flag='GET', url=url, params=search_params)

        if response.status_code != 200:
            if response.status_code == 401:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            else:
                raise InternalError()

        camera_response_array = response.json()
        camera_processed = []
        for current_object in camera_response_array:
            camera_processed.append(Camera.process_json(**current_object))

        return camera_processed
Exemplo n.º 16
0
    def write_camera(self, **kwargs):

        """
        add or update camera in the database.

        Parameters
        ----------
            camera_type : str
                Type of camera.
                Allowed values: 'ip', 'non_ip', 'stream'.
                |  This parameter is required for adding camera.
            is_active_image : bool
                Whether the camera is active and can get images.
                This field can identify true/false case-insensitively and 0/1.
                |  This parameter is required for adding camera.
            is_active_video : bool
                Whether the camera is active and can get video.
                This field can identify true/false case-insensitively and 0/1.
                |  This parameter is required for adding camera.
            ip : str
                (IP camera only) IP address of the camera.
                |  This parameter is required for adding an IP camera.
            snapshot_url : str
                (non-IP camera only) Url to retrieve snapshots from the camera.
                |  This parameter is required for adding a non-IP camera.
            m3u8_url : str
                (Stream camera only) Url to retrieve stream from the camera.
                |  This parameter is required for adding a stream camera.
            cameraID : str
                CameraID of the camera to be updated.
                |  This parameter is required for updating camera.

        Warning
        -------
            Including a cameraID in your write_camera request will update and overwrite the
            corresponding camera information in the database.
            Please ensure that the updated information is correct.

        Other Parameters
        ----------------
            legacy_cameraID : int, optional
                Original ID of the camera in SQL database.
            source : str, optional
                Source of camera.
            latitude : int or float, optional
                Latitude of the camera location.
            longitude : int or float, optional
                Longitude of the camera location.
            country : str, optional
                Country which the camera locates at.
            state : str, optional
                State which the camera locates at.
            city : str, optional
                City which the camera locates at.
            resolution_width : int, optional
                Resolution width of the camera.
            resolution_height : int, optional
                Resolution height of the camera.
            utc_offset : int, optional
                Time difference between UTC and the camera location.
            timezone_id : str, optional
                Time zone ID of the camera location.
            timezone_name : str, optional
                Time zone name of the camera location.
            reference_logo : str, optional
                Reference logo of the camera.
            reference_url : str, optional
                Reference url of the camera.
            port : str or int, optional
                (ip_camera only) Port to connect to camera.
            brand : str, optional
                (ip_camera only) Brand of the camera.
            model : str, optional
                (ip_camera only) Model of the camera.
            image_path : str, optional
                (ip_camera only) Path to retrieve images from the camera.
            video_path : str, optional
                (ip_camera only) Path to retrieve video from the camera.

        Raises
        ------
            AuthenticationError
                If the client secret of this client object does not match the clientID.
            FormatError
                Informartion of invalid parameter or unexpected paramters.
            ResourceConflictError
                The legacy_cameraID already exist in the database.
            InternalError
                If there is an API internal error.
            ResourceNotFoundError
                If no camera exists with the cameraID specified in the parameter.

                Or If the client id of this client object does not match any client
                in the database.

        Returns
        -------
        str
            The camera ID for the successfully added or updated camera.

        Note
        ----
        When adding or updating a camera you must supply the corresponding required parameters
        and may also include any number of the optional parameters defined below in
        'Other Parameters.

        When Adding a new camera:
        Do not include any cameraID when adding new cameras to the database.
        When the camera is added to the database, a new cameraID will be assigned and returned
        to the user.

        When updating an existing camera in the database you must include the corresponding
        cameraID and any fields you wish to update.
        If in any occasion you need to change an existing camera to a different type,
        you must include the corresponding retrieval method data.
        (i.e. To change an IP camera to non-ip camera, you must include values of snapshot_url
        and camera_type) Updating field in retrieval method requires you to also specify the
        type of camera. (i.e. To change the image_path of an IP camera, you should specify the
        camera_type and image_path)

        """

        self._check_args(kwargs=kwargs, legal_args=self._camera_fields)

        if self.token is None:
            self._request_token()

        operation = 'POST' if kwargs.get('cameraID') is None else 'PUT'

        if kwargs.get('camera_type') == 'ip':
            kwargs['retrieval'] = {
                'ip': kwargs.pop('ip', None),
                'port': kwargs.pop('port', None),
                'brand': kwargs.pop('brand', None),
                'model': kwargs.pop('model', None),
                'image_path': kwargs.pop('image_path', None),
                'video_path': kwargs.pop('video_path', None)
            }
            kwargs['retrieval'] = json.dumps(kwargs['retrieval'], sort_keys=True)

        elif kwargs.get('camera_type') == 'non_ip':
            kwargs['retrieval'] = {
                'snapshot_url': kwargs.pop('snapshot_url', None)
            }
            kwargs['retrieval'] = json.dumps(kwargs['retrieval'])
        elif kwargs.get('camera_type') == 'stream':
            kwargs['retrieval'] = {
                'm3u8_url': kwargs.pop('m3u8_url', None)
            }
            kwargs['retrieval'] = json.dumps(kwargs['retrieval'])
        kwargs['type'] = kwargs.pop('camera_type', None)

        if operation == 'POST':
            url = Client.base_URL + 'cameras/create'
            temp_response = requests.post(url, data=kwargs, headers=self.header_builder())
        else:
            url = Client.base_URL + 'cameras/' + kwargs.pop('cameraID')
            temp_response = requests.put(url, data=kwargs, headers=self.header_builder())

        response = self._check_token(temp_response, flag=operation, url=url, data=kwargs)

        if response.status_code != 201 and response.status_code != 200:
            if response.status_code == 403:
                raise AuthenticationError(response.json()['message'])
            elif response.status_code == 422:
                raise FormatError(response.json()['message'])
            elif response.status_code == 409:
                raise ResourceConflictError(response.json()['message'])
            elif response.status_code == 404:
                raise ResourceNotFoundError(response.json()['message'])
            else:
                raise InternalError()

        return response.json()['cameraID']