コード例 #1
0
ファイル: signing.py プロジェクト: Arinzeokeke/reddit
def valid_signature(payload, signature):
    """Checks if `signature` matches `payload`.

    `Signature` (at least as of version 1) be of the form:

       {global_version}:{platform}:{version}:{signature}

    where:

      * global_version (currently hard-coded to be "1") can be used to change
            this header's underlying schema later if needs be.  As such, can
            be treated as a protocol version.
      * platform is the client platform type (generally "ios" or "android")
      * version is the client's token version (can be updated and incremented
            per app build as needs be.
      * signature is the hmac of the request's POST body with the token derived
            from the above three parameters via `get_secret_token`
    """
    result = Storage(
        global_version=-1,
        platform=None,
        version=-1,
        mac=None,
        valid=False,
        epoch=None,
        error=ERRORS.UNKNOWN,
    )

    sig_match = SIG_HEADER_RE.match(signature or "")
    if not sig_match:
        result.error = ERRORS.INVALID_FORMAT
        return result

    sig_header_dict = sig_match.groupdict()
    # we're matching \d so this shouldn't throw a TypeError
    result.global_version = int(sig_header_dict['global_version'])
    # incrementing this value is drastic.  We can't validate a token protocol
    # we don't understand.
    if result.global_version > GLOBAL_TOKEN_VERSION:
        result.error = ERRORS.UNKOWN_GLOBAL_VERSION
        return result

    # currently there's only one version, but here's where we'll eventually
    # patch in more.
    sig_match = SIG_CONTENT_V1_RE.match(sig_header_dict['payload'])
    if not sig_match:
        result.error = ERRORS.UNPARSEABLE
        return result

    result.update(sig_match.groupdict())
    result.version = int(result.version)
    result.epoch = int(result.epoch)

    # verify that the token provided hasn't been invalidated
    if is_invalid_token(result.platform, result.version):
        result.error = ERRORS.INVALIDATED_TOKEN
        return result

    if not valid_epoch(result.platform, result.epoch):
        result.error = ERRORS.EXPIRED_TOKEN
        return result

    # get the expected secret used to verify this request.
    secret_token = get_secret_token(
        result.platform,
        result.version,
        global_version=result.global_version,
    )
    result.valid = constant_time_compare(
        result.mac,
        versioned_hmac(
            secret_token,
            epoch_wrap(result.epoch, payload),
            result.global_version
        ),
    )
    if result.valid:
        result.error = None
    else:
        result.error = ERRORS.SIGNATURE_MISMATCH

    return result
コード例 #2
0
def valid_signature(payload, signature):
    """Checks if `signature` matches `payload`.

    `Signature` (at least as of version 1) be of the form:

       {global_version}:{platform}:{version}:{signature}

    where:

      * global_version (currently hard-coded to be "1") can be used to change
            this header's underlying schema later if needs be.  As such, can
            be treated as a protocol version.
      * platform is the client platform type (generally "ios" or "android")
      * version is the client's token version (can be updated and incremented
            per app build as needs be.
      * signature is the hmac of the request's POST body with the token derived
            from the above three parameters via `get_secret_token`
    """
    result = Storage(
        global_version=-1,
        platform=None,
        version=-1,
        mac=None,
        valid=False,
        epoch=None,
        error=ERRORS.UNKNOWN,
    )

    sig_match = SIG_HEADER_RE.match(signature or "")
    if not sig_match:
        result.error = ERRORS.INVALID_FORMAT
        return result

    sig_header_dict = sig_match.groupdict()
    # we're matching \d so this shouldn't throw a TypeError
    result.global_version = int(sig_header_dict['global_version'])
    # incrementing this value is drastic.  We can't validate a token protocol
    # we don't understand.
    if result.global_version > GLOBAL_TOKEN_VERSION:
        result.error = ERRORS.UNKOWN_GLOBAL_VERSION
        return result

    # currently there's only one version, but here's where we'll eventually
    # patch in more.
    sig_match = SIG_CONTENT_V1_RE.match(sig_header_dict['payload'])
    if not sig_match:
        result.error = ERRORS.UNPARSEABLE
        return result

    result.update(sig_match.groupdict())
    result.version = int(result.version)
    result.epoch = int(result.epoch)

    # verify that the token provided hasn't been invalidated
    if is_invalid_token(result.platform, result.version):
        result.error = ERRORS.INVALIDATED_TOKEN
        return result

    if not valid_epoch(result.platform, result.epoch):
        result.error = ERRORS.EXPIRED_TOKEN
        return result

    # get the expected secret used to verify this request.
    secret_token = get_secret_token(
        result.platform,
        result.version,
        global_version=result.global_version,
    )
    result.valid = constant_time_compare(
        result.mac,
        versioned_hmac(secret_token, epoch_wrap(result.epoch, payload),
                       result.global_version),
    )
    if result.valid:
        result.error = None
    else:
        result.error = ERRORS.SIGNATURE_MISMATCH

    return result