def __validate_digit(self, var, message):
     if six.PY3:
         if not isinstance(var, (int)) and not var.isdigit():
             raise AuthyFormatException(message)
     else:
         if not isinstance(var, (int, long)) and not var.isdigit():
             raise AuthyFormatException(message)
    def clean_logos(self, logos):
        """
        Validate logos input.
        :param list logos:
        :return list logos:
        """
        if not len(logos):
            return logos  # Allow nil hash
        if not isinstance(logos, list):
            raise AuthyFormatException(
                'Invalid logos list. Only res and url required')

        temp_array = {}
        clean_logos = []

        for logo in logos:

            if not isinstance(logo, dict):
                raise AuthyFormatException('Invalid logo type')

            for l in logo:
                # We ignore any additional parameter on the logos, and truncate
                # string size to the maximum allowed.
                if l == 'res':
                    temp_array['res'] = logo[l][:MAX_STRING_SIZE]
                elif l == 'url':
                    temp_array['url'] = logo[l][:MAX_STRING_SIZE]
                else:
                    raise AuthyFormatException(
                        'Invalid logos list. Only res and url required')

            clean_logos.append(temp_array)
            temp_array = {}

        return clean_logos
Beispiel #3
0
    def send_request(self, user_id, message, seconds_to_expire=None, details={}, hidden_details={}, logos=[]):
        """
        OneTouch verification request. Sends a request for Auth App. For more info https://www.twilio.com/docs/api/authy/authy-onetouch-api
        :param string user_id: user_id User's authy id stored in your database
        :param string message: Required, the message shown to the user when the approval request arrives.
        :param number seconds_to_expire: Optional, defaults to 120 (two minutes).
        :param dict details:  For example details['Requested by'] = 'MacBook Pro, Chrome'; it will be displayed on Authy app
        :param dict hidden_details: Same usage as detail except this detail is not shown in Authy app
        :param list logos: Contains the logos that will be shown to user. The logos parameter is expected to be an array of objects, each object with two fields: res (values are default,low,med,high) and url
        :return OneTouchResponse: the server response Json Object
        """

        if not user_id or not isinstance(user_id, int):
            raise AuthyFormatException('Invalid authy id, user id is requred and must be an integer value.')

        if not message:
            raise AuthyFormatException('Invalid message - should not be empty. It is required')

        data = {
            "message": message[:MAX_STRING_SIZE],
            "seconds_to_expire": seconds_to_expire,
            "details":self.__clean_inputs(details),
            'hidden_details': self.__clean_inputs(hidden_details),
            'logos': self.clean_logos(logos)
        }

        request_url = "/onetouch/json/users/{0}/approval_requests".format(user_id)
        response = self.post(request_url, data)
        return OneTouchResponse(self, response)
Beispiel #4
0
    def verification_start(self, phone_number, country_code, via='sms',
                           locale=None, code_length=4):
        """
        :param string phone_number: stored in your databse or you provided while creating new user.
        :param string country_code: stored in your databse or you provided while creating new user.
        :param string via: verification method either sms or call
        :param string locale: optional default none
        :param number code_length: optional default 4
        :return:
        """

        if via != 'sms' and via != 'call':
            raise AuthyFormatException("Invalid Via. Expected 'sms' or 'call'.")

        options = {
            'phone_number': phone_number,
            'country_code': country_code,
            'via': via
        }

        if locale:
            options['locale'] = locale

        try:
            cl = int(code_length)
            if cl < 4 or cl > 10:
                raise ValueError
            options['code_length'] = cl
        except ValueError:
            raise AuthyFormatException(
                "Invalid code_length. Expected numeric value from 4-10.")

        resp = self.post("/protected/json/phones/verification/start", options)
        return Phone(self, resp)
Beispiel #5
0
    def _validate_request(self, user_id, message):
        if not user_id or not isinstance(user_id, int):
            raise AuthyFormatException(
                'Invalid authy id, user id is required and must be an integer value.')

        if not message:
            raise AuthyFormatException(
                'Invalid message - should not be empty. It is required')
 def __validate(self, token, device_id):
     self.__validate_digit(token, "Invalid Token. Only digits accepted.")
     self.__validate_digit(device_id,
                           "Invalid Authy id. Only digits accepted.")
     length = len(str(token))
     if length < MIN_TOKEN_SIZE or length > MAX_TOKEN_SIZE:
         raise AuthyFormatException("Invalid Token. Unexpected length.")
Beispiel #7
0
 def __validate(self, token, device_id):
     self.__validate_digit(token, "Invalid Token. Only digits accepted.")
     self.__validate_digit(device_id,
                           "Invalid Authy id. Only digits accepted.")
     length = len(token)
     if length < 6 or length > 10:
         raise AuthyFormatException("Invalid Token. Unexpected length.")
Beispiel #8
0
    def verification_start(self,
                           phone_number,
                           country_code,
                           via='sms',
                           locale=None):
        """

        :param string phone_number: stored in your databse or you provided while creating new user.
        :param string country_code: stored in your databse or you provided while creating new user.
        :param string via: verification method either sms or call
        :param string locale: optional default none
        :return:
        """

        if via != 'sms' and via != 'call':
            raise AuthyFormatException(
                "Invalid Via. Expected 'sms' or 'call'.")

        options = {
            'phone_number': phone_number,
            'country_code': country_code,
            'via': via
        }

        if locale:
            options['locale'] = locale

        resp = self.post("/protected/json/phones/verification/start", options)
        return Phone(self, resp)
    def validate_one_touch_signature(self, signature, nonce, method, url,
                                     params):
        """
        Function to validate signature in X-Authy-Signature key of headers.

        :param string signature: X-Authy-Signature key of headers.
        :param string nonce: X-Authy-Signature-Nonce key of headers.
        :param string method: GET or POST - configured in app settings for OneTouch.
        :param string url: base callback url.
        :param dict params: params sent by Authy.
        :return bool: True if calculated signature and X-Authy-Signature are identical else False.
        """
        if not signature or not isinstance(signature, str):
            raise AuthyFormatException(
                "Invalid signature - should not be empty. It is required")

        if not nonce:
            raise AuthyFormatException(
                "Invalid nonce - should not be empty. It is required")

        if not method or not ('get' == method.lower()
                              or 'post' == method.lower()):
            raise AuthyFormatException(
                "Invalid method - should not be empty. It is required")

        if not params or not isinstance(params, dict):
            raise AuthyFormatException(
                "Invalid params - should not be empty. It is required")

        query_params = self.__make_http_query(params)
        # Sort and replace encoded  params in case-sensitive order
        sorted_params = '&'.join(
            sorted(
                query_params.replace('/', '%2F').replace('%20',
                                                         '+').split('&')))
        sorted_params = re.sub("\\%5B([0-9])*\\%5D", "%5B%5D", sorted_params)
        sorted_params = re.sub("\\=None", "=", sorted_params)
        data = nonce + "|" + method + "|" + url + "|" + sorted_params
        try:
            calculated_signature = base64.b64encode(
                hmac.new(self.api_key.encode(), data.encode(),
                         hashlib.sha256).digest())
            return calculated_signature.decode() == signature
        except:
            calculated_signature = base64.b64encode(
                hmac.new(self.api_key, data, hashlib.sha256).digest())
            return calculated_signature == signature
Beispiel #10
0
 def __validate_code_length(self, code_length):
     try:
         cl = int(code_length)
         if cl < 4 or cl > 10:
             raise ValueError
         return cl
     except ValueError:
         raise AuthyFormatException(
             "Invalid code_length. Expected numeric value from 4-10.")
Beispiel #11
0
 def __validate_channel(self, via):
     if via != 'sms' and via != 'call':
         raise AuthyFormatException("Invalid Via. Expected 'sms' or 'call'.")
Beispiel #12
0
 def __validate_digit(self, var, message):
     # PEP 0237: Essentially, long renamed to int.
     if not isinstance(var, int) and not var.isdigit():
         raise AuthyFormatException(message)