This repository has been archived by the owner on Mar 15, 2018. It is now read-only.
/
utils.py
125 lines (98 loc) · 3.87 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import base64
from functools import partial
import hashlib
import time
import uuid
from django.conf import settings
from django.contrib.auth.models import User as DjangoUser
from django.db.models import Q
import commonware.log
from users.models import UserProfile, BlacklistedUsername
log = commonware.log.getLogger('z.users')
class EmailResetCode():
@classmethod
def create(cls, user_id, email):
"""Encode+Hash an email for a reset code. This is the new email."""
data = [user_id, email]
data.append(int(time.time()))
token = ",".join([str(i) for i in data])
secret = cls.make_secret(token)
return base64.urlsafe_b64encode(token), secret
@classmethod
def parse(cls, code, hash):
"""Extract a user id and an email from a code and validate against a
hash. The hash ensures us the email address hasn't changed and that
the email address matches the user id. This will raise
``ValueError`` if the hash fails or if the code is over 48 hours
old."""
try:
decoded = base64.urlsafe_b64decode(str(code))
user_id, mail, req_time = decoded.split(',')
except (ValueError, TypeError):
# Data is broken
raise ValueError
if cls.make_secret(decoded) != hash:
log.info(u"[Tampering] Email reset data does not match hash")
raise ValueError
# Is the request over 48 hours old?
age = time.time() - int(req_time)
if age > 48 * 60 * 60:
raise ValueError
return int(user_id), mail
@classmethod
def make_secret(cls, token):
key = settings.SECRET_KEY
return hashlib.sha256("%s%s" % (token, key)).hexdigest()
class UnsubscribeCode():
@classmethod
def create(cls, email):
"""Encode+Hash an email for an unsubscribe code."""
secret = cls.make_secret(email)
return base64.urlsafe_b64encode(email), secret
@classmethod
def parse(cls, code, hash):
try:
decoded = base64.urlsafe_b64decode(str(code))
mail = decoded
except (ValueError, TypeError):
# Data is broken
raise ValueError
if cls.make_secret(decoded) != hash:
log.info(u"[Tampering] Unsubscribe link data does not match hash")
raise ValueError
return mail
@classmethod
def make_secret(cls, token):
key = settings.SECRET_KEY
return hashlib.sha256("%s%s" % (token, key)).hexdigest()
def get_task_user():
"""
Returns a user object. This user is suitable for assigning to
cron jobs or long running tasks.
"""
return UserProfile.objects.get(pk=settings.TASK_USER_ID)
def find_users(email):
"""
Given an email find all the possible users, by looking in
users and in their history.
"""
return UserProfile.objects.filter(Q(email=email) |
Q(history__email=email)).distinct()
def autocreate_username(candidate, tries=1):
"""Returns a unique valid username."""
max_tries = settings.MAX_GEN_USERNAME_TRIES
from amo.utils import slugify, SLUG_OK
make_u = partial(slugify, ok=SLUG_OK, lower=True, spaces=False,
delimiter='-')
adjusted_u = make_u(candidate)
if tries > 1:
adjusted_u = '%s%s' % (adjusted_u, tries)
if (BlacklistedUsername.blocked(adjusted_u) or adjusted_u == ''
or tries > max_tries or len(adjusted_u) > 255):
log.info('username blocked, empty, max tries reached, or too long;'
' username=%s; max=%s' % (adjusted_u, max_tries))
return autocreate_username(uuid.uuid4().hex[0:15])
if (UserProfile.objects.filter(username=adjusted_u).count() or
DjangoUser.objects.filter(username=adjusted_u).count()):
return autocreate_username(candidate, tries=tries + 1)
return adjusted_u