def test_email_address_is_encoded_in_sent_verification_link(self): address = '*****@*****.**' encoded = encode_for_querystring(address) self.hit_email_spt('add-email', address) last_email = self.get_last_email() assert "~alice/emails/verify.html?email2=" + encoded in last_email[ 'body_text']
def get_email_verification_link(self, c, email, *packages): """Get a link to complete an email verification workflow. :param Cursor c: the cursor to use :param unicode email: the email address to be verified :param packages: :py:class:`~gratipay.models.package.Package` objects for which a successful verification will also entail verification of ownership of the package :returns: a URL by which to complete the verification process """ self.app.add_event( c , 'participant' , dict(id=self.id, action='add', values=dict(email=email)) ) nonce = self.get_email_verification_nonce(c, email) if packages: self.start_package_claims(c, nonce, *packages) link = "{base_url}/~{username}/emails/verify.html?email={encoded_email}&nonce={nonce}" return link.format( base_url=gratipay.base_url , username=self.username_lower , encoded_email=encode_for_querystring(email) , nonce=nonce )
def hit_verify_spt(self, email, nonce, username='******', should_fail=False): # Email address is encoded in url. url = '/~%s/emails/verify.html?email2=%s&nonce=%s' url %= (username, encode_for_querystring(email), nonce) f = self.client.GxT if should_fail else self.client.GET return f(url, auth_as=username)
def test_email_verification_is_backwards_compatible(self): """Test email verification still works with 'email2' field in verification link. """ username = '******' email = '*****@*****.**' self.hit_email_spt('add-email', email) nonce = self.alice.get_email(email).nonce url = '/~%s/emails/verify.html?email2=%s&nonce=%s' url %= (username, encode_for_querystring(email), nonce) self.client.GET(url, auth_as=username) expected = email actual = P(username).email_address assert expected == actual
def get_email_verification_link(self, c, email, *packages): """Get a link to complete an email verification workflow. :param Cursor c: the cursor to use :param unicode email: the email address to be verified :param packages: :py:class:`~gratipay.models.package.Package` objects for which a successful verification will also entail verification of ownership of the package :returns: a URL by which to complete the verification process """ self.app.add_event( c, 'participant', dict(id=self.id, action='add', values=dict(email=email))) nonce = self.get_email_verification_nonce(c, email) if packages: self.start_package_claims(c, nonce, *packages) link = "{base_url}/~{username}/emails/verify.html?email2={encoded_email}&nonce={nonce}" return link.format(base_url=gratipay.base_url, username=self.username_lower, encoded_email=encode_for_querystring(email), nonce=nonce)
def test_email_address_is_encoded_in_sent_verification_link(self): address = '*****@*****.**' encoded = encode_for_querystring(address) self.hit_email_spt('add-email', address) last_email = self.get_last_email() assert "~alice/emails/verify.html?email2="+encoded in last_email['body_text']
def verify_email(self, email, nonce, username='******', should_fail=False): # Email address is encoded in url. url = '/~%s/emails/verify.html?email2=%s&nonce=%s' url %= (username, encode_for_querystring(email), nonce) f = self.client.GxT if should_fail else self.client.GET return f(url, auth_as=username)
def test_efq_doesnt_accept_bytes(self): with self.assertRaises(TypeError): encode_for_querystring(b'TheEnterprise')
def test_efq_replaces_equals_with_tilde(self): assert encode_for_querystring('TheEnterprise') == 'VGhlRW50ZXJwcmlzZQ~~'
def test_efq_replaces_slash_with_underscore(self): # TheEnter?prise => VGhlRW50ZXI/cHJpc2U= assert encode_for_querystring('TheEnter?prise') == 'VGhlRW50ZXI_cHJpc2U~'
def add_email(self, email): """Add an email address for a participant. This is called when adding a new email address, and when resending the verification email for an unverified email address. :param unicode email: the email address to add :returns: ``None`` :raises EmailAlreadyVerified: if the email is already verified for this participant :raises EmailTaken: if the email is verified for a different participant :raises TooManyEmailAddresses: if the participant already has 10 emails :raises Throttled: if the participant adds too many emails too quickly """ # Check that this address isn't already verified owner = self.db.one( """ SELECT p.username FROM emails e INNER JOIN participants p ON e.participant_id = p.id WHERE e.address = %(email)s AND e.verified IS true """, locals()) if owner: if owner == self.username: raise EmailAlreadyVerified(email) else: raise EmailTaken(email) if len(self.get_emails()) > 9: raise TooManyEmailAddresses(email) nonce = str(uuid.uuid4()) verification_start = utcnow() try: with self.db.get_cursor() as c: self.app.add_event( c, 'participant', dict(id=self.id, action='add', values=dict(email=email))) c.run( """ INSERT INTO emails (address, nonce, verification_start, participant_id) VALUES (%s, %s, %s, %s) """, (email, nonce, verification_start, self.id)) except IntegrityError: nonce = self.db.one( """ UPDATE emails SET verification_start=%s WHERE participant_id=%s AND address=%s AND verified IS NULL RETURNING nonce """, (verification_start, self.id, email)) if not nonce: return self.add_email(email) base_url = gratipay.base_url username = self.username_lower encoded_email = encode_for_querystring(email) link = "{base_url}/~{username}/emails/verify.html?email2={encoded_email}&nonce={nonce}" self.app.email_queue.put(self, 'verification', email=email, link=link.format(**locals()), include_unsubscribe=False) if self.email_address: self.app.email_queue.put( self, 'verification_notice', new_email=email, include_unsubscribe=False # Don't count this one against their sending quota. # It's going to their own verified address, anyway. , _user_initiated=False)