-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.py
138 lines (107 loc) · 4.65 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
126
127
128
129
130
131
132
133
134
135
136
137
138
from datetime import date
from django.contrib.auth import get_user_model
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils import six
from django.utils.crypto import constant_time_compare, salted_hmac
from django.utils.encoding import force_bytes
from django.utils.http import base36_to_int, int_to_base36
from .compat import urlsafe_base64_encode
from .conf import settings
try:
from django.contrib.sites.shortcuts import get_current_site
except ImportError: # pragma: no cover
from django.contrib.sites.models import get_current_site
try:
from django.db.models.signals import post_migrate
except ImportError: # pragma: no cover
from django.db.models.signals import post_syncdb as post_migrate
if settings.USERS_CREATE_SUPERUSER:
try:
# create_superuser is removed in django 1.7
from django.contrib.auth.management import create_superuser
except ImportError: # pragma: no cover
pass
else:
# Prevent interactive question about wanting a superuser created.
from django.contrib.auth import models as auth_app
post_migrate.disconnect(
create_superuser,
sender=auth_app,
dispatch_uid='django.contrib.auth.management.create_superuser')
def auto_create_superuser(sender, **kwargs):
if not settings.USERS_CREATE_SUPERUSER:
return
email = settings.USERS_SUPERUSER_EMAIL
password = settings.USERS_SUPERUSER_PASSWORD
User = get_user_model()
try:
User.base_objects.get(email=email)
except User.DoesNotExist:
print('Creating superuser ({0}:{1})'.format(email, password))
User.objects.create_superuser(email, password)
post_migrate.connect(auto_create_superuser, sender=None)
class EmailActivationTokenGenerator(object):
def make_token(self, user):
return self._make_token_with_timestamp(user, self._num_days(self._today()))
def check_token(self, user, token):
"""
Check that a activation token is correct for a given user.
"""
# Parse the token
try:
ts_b36, hash = token.split('-')
except ValueError:
return False
try:
ts = base36_to_int(ts_b36)
except ValueError:
return False
# Check that the timestamp/uid has not been tampered with
if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
return False
# Check the timestamp is within limit
if (self._num_days(self._today()) - ts) > settings.USERS_EMAIL_CONFIRMATION_TIMEOUT_DAYS:
return False
return True
def _make_token_with_timestamp(self, user, timestamp):
ts_b36 = int_to_base36(timestamp)
key_salt = 'users.utils.EmailActivationTokenGenerator'
login_timestamp = '' if user.last_login is None else \
user.last_login.replace(microsecond=0, tzinfo=None)
value = (six.text_type(user.pk) + six.text_type(user.email) +
six.text_type(login_timestamp) + six.text_type(timestamp))
hash = salted_hmac(key_salt, value).hexdigest()[::2]
return '%s-%s' % (ts_b36, hash)
@staticmethod
def _num_days(dt):
return (dt - date(2001, 1, 1)).days
@staticmethod
def _today():
# Used for mocking in tests
return date.today()
def send_activation_email(
user=None, request=None, from_email=None,
subject_template='users/activation_email_subject.html',
email_template='users/activation_email.html', html_email_template=None):
if not user.is_active and settings.USERS_VERIFY_EMAIL:
token_generator = EmailActivationTokenGenerator()
current_site = get_current_site(request)
context = {
'email': user.email,
'site': current_site,
'expiration_days': settings.USERS_EMAIL_CONFIRMATION_TIMEOUT_DAYS,
'user': user,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': token_generator.make_token(user=user),
'protocol': 'https' if request.is_secure() else 'http',
}
subject = render_to_string(subject_template, context)
# email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
body = render_to_string(email_template, context)
email_message = EmailMultiAlternatives(subject, body, from_email, [user.email])
if html_email_template is not None:
html_email = render_to_string(html_email_template, context)
email_message.attach_alternative(html_email, 'text/html')
email_message.send()