Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
rename hash to nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
Changaco committed Oct 3, 2014
1 parent 18916a5 commit 15d7692
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 40 deletions.
5 changes: 2 additions & 3 deletions branch.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
BEGIN;
ALTER TYPE email_address_with_confirmation ADD ATTRIBUTE hash text;
ALTER TYPE email_address_with_confirmation ADD ATTRIBUTE ctime timestamp with time zone;
ALTER TYPE email_address_with_confirmation ADD ATTRIBUTE nonce text;
ALTER TYPE email_address_with_confirmation ADD ATTRIBUTE ctime timestamp with time zone;
END;

16 changes: 8 additions & 8 deletions gratipay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,26 +557,26 @@ def update_email(self, email, confirmed=False):
if email == current_email and was_confirmed:
return self.email
if not confirmed:
hash_string = str(uuid.uuid4())
nonce = str(uuid.uuid4())
ctime = utcnow()
else:
hash_string = ctime = None
nonce = ctime = None
with self.db.get_cursor() as c:
add_event(c, 'participant', dict(id=self.id, action='set', values=dict(current_email=email)))
r = c.one("UPDATE participants SET email = ROW(%s, %s, %s, %s) WHERE username=%s RETURNING email"
, (email, confirmed, hash_string, ctime, self.username)
, (email, confirmed, nonce, ctime, self.username)
)
self.set_attributes(email=r)
if not confirmed:
self.send_email(VERIFICATION_EMAIL, link=self.get_verification_link())
return r

def verify_email(self, hash_string):
def verify_email(self, nonce):
if getattr(self.email, 'confirmed', False):
return 0 # Verified
original_hash = getattr(self.email, 'hash', '')
expected_nonce = getattr(self.email, 'nonce', '')
email_ctime = getattr(self.email, 'ctime', '')
if constant_time_compare(original_hash, hash_string):
if constant_time_compare(expected_nonce, nonce):
if (utcnow() - email_ctime) < EMAIL_HASH_TIMEOUT:
self.update_email(self.email.address, True)
return 0 # Verified
Expand All @@ -588,9 +588,9 @@ def verify_email(self, hash_string):
def get_verification_link(self):
scheme = gratipay.canonical_scheme
host = gratipay.canonical_host
hash = self.email.hash
nonce = self.email.nonce
username = self.username_lower
link = "{scheme}://{host}/{username}/verify-email.html?hash={hash}"
link = "{scheme}://{host}/{username}/verify-email.html?nonce={nonce}"
return link.format(**locals())

def send_email(self, message, **params):
Expand Down
4 changes: 2 additions & 2 deletions tests/py/fixtures/TestEmailJson.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
interactions:
- request:
body: '{"async": false, "message": {"from_name": "Gratipay", "text": "\nWelcome
to Gratipay! Verify your email address:\n\nhttp:///alice/verify-email.html?hash=e6f85c8c-5ea8-4803-b620-2f6ed3e79657\n",
to Gratipay! Verify your email address:\n\nhttp:///alice/verify-email.html?nonce=e6f85c8c-5ea8-4803-b620-2f6ed3e79657\n",
"from_email": "[email protected]", "to": [{"email": "[email protected]",
"name": "alice"}], "html": "\nWelcome to Gratipay!\n<br><br>\n<a href=\"http:///alice/verify-email.html?hash=e6f85c8c-5ea8-4803-b620-2f6ed3e79657\">Verify
"name": "alice"}], "html": "\nWelcome to Gratipay!\n<br><br>\n<a href=\"http:///alice/verify-email.html?nonce=e6f85c8c-5ea8-4803-b620-2f6ed3e79657\">Verify
your email address</a>.\n", "subject": "Welcome to Gratipay!"}, "send_at": null,
"key": "Phh_Lm3RdPT5blqOPY4dVQ", "ip_pool": null}'
headers: {}
Expand Down
2 changes: 1 addition & 1 deletion tests/py/test_close.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def test_cpi_clears_personal_information(self):
, anonymous_receiving=True
, number='plural'
, avatar_url='img-url'
, email=('[email protected]', True, 'samplehash', utcnow())
, email=('[email protected]', True, 'samplenonce', utcnow())
, claimed_time='now'
, session_token='deadbeef'
, session_expires='2000-01-01'
Expand Down
14 changes: 7 additions & 7 deletions tests/py/test_participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,23 +233,23 @@ def test_can_update_email(self, send_email):
@mock.patch.object(Participant, 'send_email')
def test_can_verify_email(self, send_email):
self.alice.update_email('[email protected]')
hash_string = Participant.from_username('alice').email.hash
r = self.alice.verify_email(hash_string)
nonce = Participant.from_username('alice').email.nonce
r = self.alice.verify_email(nonce)
assert r == 0
actual = Participant.from_username('alice').email.confirmed
assert actual == True

@mock.patch.object(Participant, 'send_email')
def test_cannot_verify_email_with_wrong_hash(self, send_email):
def test_cannot_verify_email_with_wrong_nonce(self, send_email):
self.alice.update_email('[email protected]')
hash_string = "some wrong hash"
r = self.alice.verify_email(hash_string)
nonce = "some wrong nonce"
r = self.alice.verify_email(nonce)
assert r == 2
actual = Participant.from_username('alice').email.confirmed
assert actual == False

@mock.patch.object(Participant, 'send_email')
def test_cannot_verify_email_with_expired_hash(self, send_email):
def test_cannot_verify_email_with_expired_nonce(self, send_email):
self.alice.update_email('[email protected]')
email = self.db.one("""
UPDATE participants
Expand All @@ -258,7 +258,7 @@ def test_cannot_verify_email_with_expired_hash(self, send_email):
RETURNING email
""")
self.alice.set_attributes(email=email)
r = self.alice.verify_email(self.alice.email.hash)
r = self.alice.verify_email(self.alice.email.nonce)
assert r == 1
actual = Participant.from_username('alice').email.confirmed
assert actual == False
Expand Down
34 changes: 17 additions & 17 deletions tests/py/test_verify_email_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def change_email_address(self, address, username, send_email, should_fail=False)
)
return response

def verify_email(self, username, hash_string, should_fail=False):
url = '/%s/verify-email.html?hash=%s' % (username , hash_string)
def verify_email(self, username, nonce, should_fail=False):
url = '/%s/verify-email.html?nonce=%s' % (username , nonce)
if should_fail:
response = self.client.GxT(url)
else:
Expand All @@ -31,31 +31,31 @@ def verify_email(self, username, hash_string, should_fail=False):

def test_verify_email_without_adding_email(self):
participant = self.make_participant('alice')
response = self.verify_email(participant.username,'sample-hash', should_fail=True)
response = self.verify_email(participant.username, 'sample-nonce', should_fail=True)
assert response.code == 404

def test_verify_email_wrong_hash(self):
def test_verify_email_wrong_nonce(self):
participant = self.make_participant('alice', claimed_time="now")
self.change_email_address('[email protected]', participant.username)
self.verify_email(participant.username,'sample-hash')
self.verify_email(participant.username, 'sample-nonce')
expected = False
actual = Participant.from_username(participant.username).email.confirmed
assert expected == actual

def test_verify_email(self):
participant = self.make_participant('alice', claimed_time="now")
self.change_email_address('[email protected]', participant.username)
hash_string = Participant.from_username(participant.username).email.hash
self.verify_email(participant.username,hash_string)
nonce = Participant.from_username(participant.username).email.nonce
self.verify_email(participant.username, nonce)
expected = True
actual = Participant.from_username(participant.username).email.confirmed
assert expected == actual

def test_email_is_not_confirmed_after_update(self):
participant = self.make_participant('alice', claimed_time="now")
self.change_email_address('[email protected]', participant.username)
hash_string = Participant.from_username(participant.username).email.hash
self.verify_email(participant.username,hash_string)
nonce = Participant.from_username(participant.username).email.nonce
self.verify_email(participant.username, nonce)
self.change_email_address('[email protected]', participant.username)
expected = False
actual = Participant.from_username(participant.username).email.confirmed
Expand All @@ -64,19 +64,19 @@ def test_email_is_not_confirmed_after_update(self):
def test_verify_email_after_update(self):
participant = self.make_participant('alice', claimed_time="now")
self.change_email_address('[email protected]', participant.username)
hash_string = Participant.from_username(participant.username).email.hash
self.verify_email(participant.username,hash_string)
nonce = Participant.from_username(participant.username).email.nonce
self.verify_email(participant.username, nonce)
self.change_email_address('[email protected]', participant.username)
hash_string = Participant.from_username(participant.username).email.hash
self.verify_email(participant.username,hash_string)
nonce = Participant.from_username(participant.username).email.nonce
self.verify_email(participant.username, nonce)
expected = True
actual = Participant.from_username(participant.username).email.confirmed
assert expected == actual

def test_hash_is_regenerated_on_update(self):
def test_nonce_is_regenerated_on_update(self):
participant = self.make_participant('alice', claimed_time="now")
self.change_email_address('[email protected]', participant.username)
hash_string_1 = Participant.from_username(participant.username).email.hash
nonce1 = Participant.from_username(participant.username).email.nonce
self.change_email_address('[email protected]', participant.username)
hash_string_2 = Participant.from_username(participant.username).email.hash
assert hash_string_1 != hash_string_2
nonce2 = Participant.from_username(participant.username).email.nonce
assert nonce1 != nonce2
4 changes: 2 additions & 2 deletions www/%username/verify-email.html.spt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ from datetime import timedelta

participant = get_participant(request, restrict=False)
qs = request.line.uri.querystring
hash_string = qs['hash'] if 'hash' in qs else ''
nonce = qs.get('nonce', '')

if not participant.email:
raise Response(404)

result = participant.verify_email(hash_string)
result = participant.verify_email(nonce)

[-----------------------------------------------------------------------------]
{% extends "templates/base.html" %}
Expand Down

0 comments on commit 15d7692

Please sign in to comment.