def _get_user_via_basic_auth(auth_header):
    """Given a basic auth header, return a User object.
    """
    try:
        creds = binascii.a2b_base64(auth_header[len('Basic '):]).split(':', 1)
    except binascii.Error:
        raise Response(400, 'Malformed "Authorization" header')
    if len(creds) != 2:
        raise Response(401)
    userid, api_key = creds
    if len(userid) == 36 and '-' in userid:
        user = _get_user_via_api_key(userid)  # For backward-compatibility
    else:
        try:
            userid = int(userid)
        except ValueError:
            raise Response(401)
        user = User.from_id(userid)
        if user.ANON or not constant_time_compare(user.participant.api_key, api_key):
            raise Response(401)
    return user
 def check_connect_token(self, token):
     return (
         self.connect_token and
         constant_time_compare(self.connect_token, token) and
         self.connect_expires > utcnow()
     )
Exemple #3
0
    def finish_email_verification(self, email, nonce):
        """Given an email address and a nonce as strings, return a three-tuple:

        - a ``VERIFICATION_*`` constant;
        - a list of packages if ``VERIFICATION_SUCCEEDED`` (``None``
          otherwise), and
        - a boolean indicating whether the participant's PayPal address was
          updated if applicable (``None`` if not).

        """
        _fail = VERIFICATION_FAILED, None, None
        if '' in (email.strip(), nonce.strip()):
            return _fail
        with self.db.get_cursor() as cursor:

            # Load an email record. Check for an address match, but don't check
            # the nonce at this point. We want to compare in constant time to
            # avoid timing attacks, and we'll do that below.

            record = self.get_email(email, cursor, and_lock=True)
            if record is None:

                # We don't have that email address on file. Maybe it used to be
                # on file but was explicitly removed (they followed an old link
                # after removing in the UI?), or maybe it was never on file in
                # the first place (they munged the querystring?).

                return _fail

            if record.nonce is None:

                # Nonces are nulled out only when updating to mark an email
                # address as verified; we always set a nonce when inserting.
                # Therefore, the main way to get a null nonce is to issue a
                # link, follow it, and follow it again.

                # All records with a null nonce should be verified, though not
                # all verified records will have a null nonce. That is, it's
                # possible to land here with an already-verified address, and
                # this is in fact expected when verifying package ownership via
                # an already-verified address.

                assert record.verified

                return VERIFICATION_REDUNDANT, None, None


            # *Now* verify that the nonce given matches the one expected, along
            # with the time window for verification.

            if not constant_time_compare(record.nonce, nonce):
                return _fail
            if (utcnow() - record.verification_start) > EMAIL_HASH_TIMEOUT:
                return _fail


            # And now we can load any packages associated with the nonce, and
            # save the address.

            packages = self.get_packages_claiming(cursor, nonce)
            paypal_updated = None
            try:
                if packages:
                    paypal_updated = False
                    self.finish_package_claims(cursor, nonce, *packages)
                self.save_email_address(cursor, email)
                has_no_paypal = not self.get_payout_routes(good_only=True)
                if packages and has_no_paypal:
                    self.set_paypal_address(email, cursor)
                    paypal_updated = True
            except IntegrityError:
                return VERIFICATION_STYMIED, None, None
            return VERIFICATION_SUCCEEDED, packages, paypal_updated
Exemple #4
0
    def finish_email_verification(self, email, nonce):
        """Given an email address and a nonce as strings, return a three-tuple:

        - a ``VERIFICATION_*`` constant;
        - a list of packages if ``VERIFICATION_SUCCEEDED`` (``None``
          otherwise), and
        - a boolean indicating whether the participant's PayPal address was
          updated if applicable (``None`` if not).

        """
        _fail = VERIFICATION_FAILED, None, None
        if '' in (email.strip(), nonce.strip()):
            return _fail
        with self.db.get_cursor() as cursor:

            # Load an email record. Check for an address match, but don't check
            # the nonce at this point. We want to compare in constant time to
            # avoid timing attacks, and we'll do that below.

            record = self.get_email(email, cursor, and_lock=True)
            if record is None:

                # We don't have that email address on file. Maybe it used to be
                # on file but was explicitly removed (they followed an old link
                # after removing in the UI?), or maybe it was never on file in
                # the first place (they munged the querystring?).

                return _fail

            if record.nonce is None:

                # Nonces are nulled out only when updating to mark an email
                # address as verified; we always set a nonce when inserting.
                # Therefore, the main way to get a null nonce is to issue a
                # link, follow it, and follow it again.

                # All records with a null nonce should be verified, though not
                # all verified records will have a null nonce. That is, it's
                # possible to land here with an already-verified address, and
                # this is in fact expected when verifying package ownership via
                # an already-verified address.

                assert record.verified

                return VERIFICATION_REDUNDANT, None, None

            # *Now* verify that the nonce given matches the one expected, along
            # with the time window for verification.

            if not constant_time_compare(record.nonce, nonce):
                return _fail
            if (utcnow() - record.verification_start) > EMAIL_HASH_TIMEOUT:
                return _fail

            # And now we can load any packages associated with the nonce, and
            # save the address.

            packages = self.get_packages_claiming(cursor, nonce)
            paypal_updated = None
            try:
                if packages:
                    paypal_updated = False
                    self.finish_package_claims(cursor, nonce, *packages)
                self.save_email_address(cursor, email)
                has_no_paypal = not self.get_payout_routes(good_only=True)
                if packages and has_no_paypal:
                    self.set_paypal_address(email, cursor)
                    paypal_updated = True
            except IntegrityError:
                return VERIFICATION_STYMIED, None, None
            return VERIFICATION_SUCCEEDED, packages, paypal_updated