def create_for_user(self, user): """ create password reset for specified user """ # support passing email address too if type(user) is unicode: userprofile = UserProfile.objects.get(profile_email=user) user = User.objects.get(id=userprofile.user_id) temp_key = token_generator.make_token(user) # save it to the password reset model password_reset = PasswordReset(user=user, temp_key=temp_key) password_reset.save() print user.id print int_to_base36(5000) # send the password reset email subject = _("Password reset email sent") message = render_to_string("profiles/email_messages/password_reset_key_message.txt", { "user": user, "uid": int_to_base36(user.id), "temp_key": temp_key, "site_url": settings.SITE_URL, "site_name": settings.SITE_NAME }) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [userprofile.profile_email]) return password_reset
def test_password_policy_on_password_reset(self): """ This makes sure the proper asserts on password policy also works on password reset """ staff_email, _ = self._setup_user(is_staff=True, password="******") success_msg = "Your Password Reset is Complete" # try to reset password, it should fail user = User.objects.get(email=staff_email) token = default_token_generator.make_token(user) uidb36 = int_to_base36(user.id) # try to do a password reset with the same password as before resp = self.client.post( "/password_reset_confirm/{0}-{1}/".format(uidb36, token), {"new_password1": "foo", "new_password2": "foo"}, follow=True, ) self.assertNotIn(success_msg, resp.content) # try to reset password with a long enough password user = User.objects.get(email=staff_email) token = default_token_generator.make_token(user) uidb36 = int_to_base36(user.id) # try to do a password reset with the same password as before resp = self.client.post( "/password_reset_confirm/{0}-{1}/".format(uidb36, token), {"new_password1": "foofoo", "new_password2": "foofoo"}, follow=True, ) self.assertIn(success_msg, resp.content)
def create(self, data=None, files=None, acceptable=None, required=None, exclude=None, request=None, request_kwargs=None): if not data['from_command']: raise Exception() data, files = self.validate_create(data=data, files=files) components = data['components'] parent = None for each in components: types = [] try: _sub_locality = AddressComponent.objects.get(name=each['ko'], parent=parent) except AddressComponent.DoesNotExist: _sub_locality, created = AddressComponent.objects.get_or_create(name=each['ko'], parent=parent, ascii_name=each['ascii'], depth=each['depth']) for each_type in each['types']: cur_type, created = AddressComponentType.objects.get_or_create(name=each_type) _sub_locality.types.add(cur_type) _sub_locality.save() parent = _sub_locality region_code = int_to_base36(parent.pk) parent = parent.parent while parent: region_code = int_to_base36(parent.pk) + ":" + region_code parent = parent.parent return self._meta.resource_instance_cls(region_code, self)
def generate_feed_token(cls, feed_pk, user_pk): user_secret_key, created_unused = FeedSecretKey.objects.get_or_create(feed_id=feed_pk) secret_key = user_secret_key.secret_key.encode('utf-8') checksum = generate_random_from_vschar_set(length=10) return encrypt_cbc(int_to_base36(int(feed_pk)) + "." + int_to_base36(int(user_pk)) + '.' + '.' + checksum, SOCIAL_SETTINGS.FEED_TOKEN_SECRET_KEY) + '.' + encrypt_cbc(checksum, secret_key)
def image_upload_to(instance, filename): """ random_key is used to prevent scraping of the website """ key = int(timezone.now().strftime('%Y%m%d%H%M%S%f')) key = int_to_base36(key) filename = '{}-{}.jpg'.format(int_to_base36(instance.key_id), key) dirs = int_to_base36(instance.key_id)[:-1] return os.sep.join(['image', instance.key_type.lower()] + list(dirs) + [filename])
def test_base36(self): # reciprocity works for n in [0, 1, 1000, 1000000]: self.assertEqual(n, http.base36_to_int(http.int_to_base36(n))) if six.PY2: self.assertEqual(sys.maxint, http.base36_to_int(http.int_to_base36(sys.maxint))) # bad input with self.assertRaises(ValueError): http.int_to_base36(-1) if six.PY2: with self.assertRaises(ValueError): http.int_to_base36(sys.maxint + 1) for n in ['1', 'foo', {1: 2}, (1, 2, 3), 3.141]: with self.assertRaises(TypeError): http.int_to_base36(n) for n in ['#', ' ']: with self.assertRaises(ValueError): http.base36_to_int(n) for n in [123, {1: 2}, (1, 2, 3), 3.141]: with self.assertRaises(TypeError): http.base36_to_int(n) # more explicit output testing for n, b36 in [(0, '0'), (1, '1'), (42, '16'), (818469960, 'django')]: self.assertEqual(http.int_to_base36(n), b36) self.assertEqual(http.base36_to_int(b36), n)
def get_absolute_update_url(self): def create_token(membro): key_salt = "cadastro.forms.AtualizarCadastroLinkForm" value = u'%s%s' % (membro.pk, membro.email) return salted_hmac(key_salt, value).hexdigest()[::2] return reverse('atualizar_cadastro', kwargs={ 'uidb36': int_to_base36(self.pk), 'ts_b36': int_to_base36((date.today() - date(2001, 1, 1)).days), 'token': create_token(self), })
def _make_token_with_timestamp(user, ip_address, timestamp): ts_b36 = int_to_base36(timestamp) uid_b36 = int_to_base36(user.id) key_salt = 'WebSocketTokenGenerator' # ws_auth_key_salt allows the user's ws token to be invalidated, it should return a string, # changing that string will invalidate the websocket token no_user_key_salt = lambda: '' custom_key_salt = getattr(user, 'ws_auth_key_salt', no_user_key_salt)() value = uid_b36 + user.password + str(ip_address) + str(custom_key_salt) + str(timestamp) hash = salted_hmac(key_salt, value).hexdigest() return '%s-%s-%s' % (ts_b36, uid_b36, hash)
def basic_view(self, request, extra_context=None): if request.method == "POST": form = self.form(request.POST, request.FILES, instance=request.user) formset = self.formset(request.POST, request.FILES, instance=request.user) if form.is_valid() and formset.is_valid(): form.save() new = formset.save() if new: site = Site.objects.get_current() t = loader.get_template("stepping_out/admin/email/add_email_confirmation.txt") for email in new: url = reverse( "%s_email_add" % self.admin_site.url_prefix, kwargs={ "token": email_token_generator.make_token(request.user, email), "eidb36": int_to_base36(email.id), "uidb36": int_to_base36(request.user.id), }, ) c = Context( { "protocol": "http", "domain": site.domain, "url": url, "admin_email": "the webmaster", # FIXME } ) send_mail("Confirm email for account", t.render(c), "noreply@%s" % site.domain, [email.email]) if len(new) == 1: messages.add_message( request, messages.SUCCESS, "An email with a confirmation link has been sent to %s." % new[0].email, ) else: messages.add_message( request, messages.SUCCESS, "Confirmation links have been sent via email to the addresses you added.", ) return HttpResponseRedirect("") else: form = self.form(instance=request.user) formset = self.formset(instance=request.user) extra_context = extra_context or {} extra_context.update({"form": form, "formset": formset}) return super(FormAdminSection, self).basic_view(request, extra_context)
def test_group_membership_acceptance_via_email_link(self): # here we are testing group_membership view function which is invoked # when the user clicks the link provided in the email # create a group new_group = self._create_group() # test user accepting group owner's invitation # check mike is no more a member of the group self.assertNotIn(self.mike, new_group.gaccess.members) # let john invite mike to join group membership_request = self.john.uaccess.create_group_membership_request(new_group, self.mike) # create the link that mike should find in his email uidb36 = int_to_base36(self.mike.id) token = default_token_generator.make_token(self.mike) url_params = {"uidb36": uidb36, "token": token, "membership_request_id": membership_request.id} url = reverse('group_membership', kwargs=url_params) # due to session requirement of the view being tested, using the Client class client = Client() # let mike click the link in the email response = client.get(url) redirect_url = '/group/{}/'.format(new_group.id) self.assertEqual(response.status_code, status.HTTP_302_FOUND) self.assertTrue(response['Location'].endswith(redirect_url)) # check mike is now a member of the group self.assertIn(self.mike, new_group.gaccess.members) # test group owner (john) accepting user (mike) request to join a group # remove mike from group self.john.uaccess.unshare_group_with_user(new_group, self.mike) # check mike is no more a member of the group self.assertNotIn(self.mike, new_group.gaccess.members) # let mike make a request to join group membership_request = self.mike.uaccess.create_group_membership_request(new_group) # create the link that john should find in his email uidb36 = int_to_base36(self.john.id) token = default_token_generator.make_token(self.john) url_params = {"uidb36": uidb36, "token": token, "membership_request_id": membership_request.id} url = reverse('group_membership', kwargs=url_params) # let john click the link response = client.get(url) redirect_url = '/group/{}/'.format(new_group.id) self.assertEqual(response.status_code, status.HTTP_302_FOUND) self.assertTrue(response['Location'].endswith(redirect_url)) # check mike is now a member of the group self.assertIn(self.mike, new_group.gaccess.members)
def setUp(self): super(PasswordResetTests, self).setUp() self.u = user(email="*****@*****.**", save=True) self.uidb36 = int_to_base36(self.u.id) self.token = default_token_generator.make_token(self.u) self.orig_debug = settings.DEBUG settings.DEBUG = True
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } subject = loader.render_to_string(subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) send_mail(subject=subject, message=email, from_email=None, recipient_list=(user.email,))
def save(self, **kwargs): email = self.cleaned_data["email"] token_generator = kwargs.get("token_generator", default_token_generator) for user in User.objects.filter(email__iexact=email): temp_key = token_generator.make_token(user) # save it to the password reset model password_reset = PasswordReset(user=user, temp_key=temp_key) password_reset.save() current_site = Site.objects.get_current() domain = unicode(current_site.domain) # send the password reset email subject = _("Password reset email sent") message = render_to_string("account/password_reset_key_message.txt", { "user": user, "uid": int_to_base36(user.id), "temp_key": temp_key, "domain": domain, }) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email], priority="high") return self.cleaned_data["email"]
def test_deki_only_user(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Skip, if MindTouch API unavailable raise SkipTest() get_current.return_value.domain = 'testserver.com' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') r = self.client.post(reverse('users.pw_reset'), {'email': '*****@*****.**'}) eq_(302, r.status_code) eq_('http://testserver/en-US/users/pwresetsent', r['location']) eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Password reset') == 0 u = User.objects.get(username='******') assert mail.outbox[0].body.find('pwreset/%s' % int_to_base36(u.id)) > 0
def save(self, subject, email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ for user in self.users_cache: ctx = { 'email': user.business_email, 'site': settings.SITE_HOSTNAME, 'uid': int_to_base36(user.pk), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } options = { 'subject': subject, 'from_email': from_email, 'to': [user.business_email], 'template_name': email_template_name, 'context': ctx } mail.notify(options)
def test_account(self): """ Test account creation. """ # Verification not required - test an active user is created. data = self.account_data("test1") settings.ACCOUNTS_VERIFICATION_REQUIRED = False response = self.client.post(reverse("signup"), data, follow=True) self.assertEqual(response.status_code, 200) users = User.objects.filter(email=data["email"], is_active=True) self.assertEqual(len(users), 1) # Verification required - test an inactive user is created, settings.ACCOUNTS_VERIFICATION_REQUIRED = True data = self.account_data("test2") emails = len(mail.outbox) response = self.client.post(reverse("signup"), data, follow=True) self.assertEqual(response.status_code, 200) users = User.objects.filter(email=data["email"], is_active=False) self.assertEqual(len(users), 1) # Test the verification email. self.assertEqual(len(mail.outbox), emails + 1) self.assertEqual(len(mail.outbox[0].to), 1) self.assertEqual(mail.outbox[0].to[0], data["email"]) # Test the verification link. new_user = users[0] verification_url = reverse("signup_verify", kwargs={ "uidb36": int_to_base36(new_user.id), "token": default_token_generator.make_token(new_user), }) response = self.client.get(verification_url, follow=True) self.assertEqual(response.status_code, 200) users = User.objects.filter(email=data["email"], is_active=True) self.assertEqual(len(users), 1)
def test_student_password_reset_reuse(self): """ Goes through the password reset flows to make sure the various password reuse policies are enforced """ student_email, _ = self._setup_user() user = User.objects.get(email=student_email) err_msg = 'You are re-using a password that you have used recently. You must have 1 distinct password' success_msg = 'Your Password Reset is Complete' token = default_token_generator.make_token(user) uidb36 = int_to_base36(user.id) # try to do a password reset with the same password as before resp = self.client.post('/password_reset_confirm/{0}-{1}/'.format(uidb36, token), { 'new_password1': 'foo', 'new_password2': 'foo' }, follow=True) self.assertPasswordResetError(resp, err_msg) # now retry with a different password resp = self.client.post('/password_reset_confirm/{0}-{1}/'.format(uidb36, token), { 'new_password1': 'bar', 'new_password2': 'bar' }, follow=True) self.assertIn(success_msg, resp.content)
def form_valid(self, form): user = form.save() if not self.domain_override: current_site = get_current_site(self.request) site_name = current_site.name domain = current_site.domain else: site_name = domain = self.domain_override if django.VERSION < (1, 6): encoded_uid = int_to_base36(user.pk) else: from django.utils.http import urlsafe_base64_encode from django.utils.encoding import force_bytes encoded_uid = urlsafe_base64_encode(force_bytes(user.pk)) c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': encoded_uid, 'user': user, 'token': self.token_generator.make_token(user), 'protocol': 'https' if self.use_https else 'http', } subject = loader.render_to_string(self.subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(self.email_template_name, c) send_mail(subject, email, self.from_email, [user.email]) if self.success_message: messages.success(self.request, self.success_message) return super(RegistrationView, self).form_valid(form)
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None, html_email_template_name=None): """ Generates a one-use only link for resetting password and sends to the user. """ from django.core.mail import EmailMultiAlternatives from django.utils.http import int_to_base36 for user in self.users_cache: c = { 'email': user.email, 'site': {'name': settings.SITE_NAME, 'url': settings.SITE_URL}, 'uid': int_to_base36(user.pk), 'user': user, 'token': token_generator.make_token(user), } subject = loader.render_to_string(subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) message = EmailMultiAlternatives(subject=subject, from_email=from_email, to=[user.email], body=email) if html_email_template_name: html_email = loader.render_to_string(html_email_template_name, c) message.attach_alternative(html_email, "text/html") message.send()
def save(self, **kwargs): email = self.cleaned_data["email"] token_generator = kwargs.get("token_generator", default_token_generator) for user in self.users: temp_key = token_generator.make_token(user) # save it to the password reset model # password_reset = PasswordReset(user=user, temp_key=temp_key) # password_reset.save() current_site = Site.objects.get_current() # send the password reset email path = reverse("account_reset_password_from_key", kwargs=dict(uidb36=int_to_base36(user.id), key=temp_key)) url = '%s://%s%s' % (app_settings.DEFAULT_HTTP_PROTOCOL, current_site.domain, path) context = {"site": current_site, "user": user, "password_reset_url": url} get_adapter().send_mail('account/email/password_reset_key', email, context) return self.cleaned_data["email"]
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Sending emails with html content only. """ for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override t = loader.get_template(email_template_name) c = Context({ 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', }) message = t.render(c) msg = EmailMessage(_("Password reset on %s") % site_name, message, config_value('EmailServer', 'DEFAULT_FROM_EMAIL'), [user.email]) msg.encoding = "utf-8" msg.content_subtype = "html" msg.send()
def save( self, domain_override=None, email_template_name="registration/password_reset_email.html", use_https=False, token_generator=default_token_generator, from_email=None, request=None, ): """ Generates a one-use only link for resetting password and sends to the user """ from django.core.mail import send_mail for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override t = loader.get_template(email_template_name) c = { "email": user.email, "domain": domain, "site_name": site_name, "uid": int_to_base36(user.id), "user": user, "token": token_generator.make_token(user), "protocol": use_https and "https" or "http", } send_mail(_("Password reset on %s") % site_name, t.render(Context(c)), from_email, [user.email])
def save(self, domain_override=None, subject_template_name='authentication/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.pk), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } subject = loader.render_to_string('authentication/password_reset_subject.txt', c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) message_text = loader.render_to_string('authentication/password_reset_email.txt', c) message_html = loader.render_to_string('authentication/password_reset_email.html', c) msg = EmailMultiAlternatives(subject, message_text, settings.DEFAULT_FROM_EMAIL, [self.user.email]) msg.attach_alternative(message_html, "text/html") msg.send()
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, request=None): """ Generates a one-use only link for resetting password and sends to the user """ # from django.core.mail import send_mail for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override t = loader.get_template(email_template_name) c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } # send_mail(_("Password reset on %s") % site_name, # t.render(Context(c)), None, [user.email]) utils.send_mail([user.email], _("Password reset on %s") % site_name, t.render(Context(c)))
def gen_reg_token(true_id, username): microsec = datetime.datetime.now().microsecond microsec_36 = int_to_base36(microsec) true_id = str(true_id) raw = '%s-%s%s-%s' % (microsec_36, true_id[:4], true_id[-4:], username) return raw
def save(self, commit=True, domain_override=None, email_template_name='registration/signup_email.html', use_https=False, token_generator=default_token_generator): user = super(UserCreationForm, self).save(commit=False) user.set_password(self.cleaned_data["password1"]) user.email = self.cleaned_data["email1"] user.is_active = False if commit: user.save() if not domain_override: current_site = Site.objects.get_current() site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override t = loader.get_template(email_template_name) c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } send_mail("Confirmation link sent on %s" % site_name, t.render(Context(c)), '*****@*****.**', [user.email]) return user
def get_password_reset_url(user, token_generator=default_token_generator): """ Generate a password-reset URL for a given user """ return reverse('password-reset-confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user)})
def _make_token_with_timestamp(self, user, timestamp): # timestamp is number of days since 2001-1-1. Converted to # base 36, this gives us a 3 digit string until about 2121 ts_b36 = int_to_base36(timestamp) # By hashing on the internal state of the user and using state # that is sure to change (the password salt will change as soon as # the password is set, at least for current Django auth, and # last_login will also change), we produce a hash that will be # invalid as soon as it is used. # We limit the hash to 20 chars to keep URL short key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator" # Ensure results are consistent across DB backends user_last_login = UserLastLogin.objects.get_by_username(user.username) if user_last_login is None: from seahub.utils.timeutils import dt login_dt = dt(user.ctime) else: login_dt = user_last_login.last_login login_timestamp = login_dt.replace(microsecond=0, tzinfo=None) value = (six.text_type(user.id) + user.enc_password + six.text_type(login_timestamp) + six.text_type(timestamp)) hash = salted_hmac(key_salt, value).hexdigest()[::2] return "%s-%s" % (ts_b36, hash)
def get_email_context_data(self, user, **kwargs): token_view_name = kwargs.get('token_view_name', self.token_view_name) if not token_view_name: raise ImproperlyConfigured("No token_view_name defined.") site = Site.objects.get_current() token = default_token_generator.make_token(user) uidb36 = int_to_base36(user.id) static_url = settings.STATIC_URL token_url = reverse(token_view_name, kwargs={'uidb36': uidb36, 'token': token}) if hasattr(self, 'request'): token_url = self.request.build_absolute_uri(token_url) if '://' not in static_url: static_url = self.request.build_absolute_uri(static_url) else: token_url = 'http://%s%s' % (site.domain, token_url) return { 'user': user, 'uid': uidb36, 'token': token, 'token_url': token_url, 'site': site, 'static_url': static_url, }
def save(self, **kwargs): email = self.cleaned_data["email"] token_generator = kwargs.get("token_generator", default_token_generator) for user in self.users: temp_key = token_generator.make_token(user) # save it to the password reset model # password_reset = PasswordReset(user=user, temp_key=temp_key) # password_reset.save() current_site = Site.objects.get_current() # send the password reset email subject = format_email_subject(_("Password Reset E-mail")) path = reverse("account_reset_password_from_key", kwargs=dict(uidb36=int_to_base36(user.id), key=temp_key)) url = 'http://%s%s' % (current_site.domain, path) message = render_to_string \ ("account/password_reset_key_message.txt", { "site": current_site, "user": user, "password_reset_url": url }) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [email]) return self.cleaned_data["email"]
def save(self, verify_email_address=False, domain_override=None, subject_template_name='emails/user_new_subject.txt', email_template_name='emails/user_new.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None, commit=True): """ Generates a one-use only link for resetting password and sends to the user. """ user = super(UserCreationForm, self).save(commit=False) user.set_password(self.cleaned_data["password1"]) user.first_name = self.cleaned_data["first_name"] user.last_name = self.cleaned_data["last_name"] user.mother_family_name = self.cleaned_data["mother_family_name"] user.is_active = not verify_email_address if commit: user.save() if verify_email_address: from django.core.mail import send_mail if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } subject = loader.render_to_string(subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) send_mail(subject, email, from_email, [user.email]) return user
def save(self, **kwargs): email = self.cleaned_data["email"] token_generator = kwargs.get("token_generator", default_token_generator) email_addresses = EmailAddress.objects.filter( email__iexact=email) for email_address in email_addresses: user = email_address.user temp_key = token_generator.make_token(user) # save it to the password reset model password_reset = PasswordReset(user=user, temp_key=temp_key) password_reset.save() # save it to the email confirmation model if not email_address.verified: EmailConfirmation.objects.create( email_address=email_address, confirmation_key=temp_key, sent=settings.GET_NOW() ) current_site = Site.objects.get_current() domain = unicode(current_site.domain) # send the password reset email subject = _("HealerSource Password Reset") message = render_to_string( "account/password_reset_key_message.txt", { "user": user, "uid": int_to_base36(user.id), "temp_key": temp_key, "domain": domain, "email": email }) from healers.utils import send_regular_mail send_regular_mail( subject, message, settings.DEFAULT_FROM_EMAIL, [user.email]) return self.cleaned_data["email"]
def test_should_send_correct_email_in_html_format_in_english_to_a_newly_created_user( self): site = get_current_site(None) user = Mock(spec=User) user.email = '*****@*****.**' user.id = 1 user.first_name = "test" language_code = "en" request = Mock() request.user.first_name = "rakoto" with patch( "django.contrib.auth.tokens.default_token_generator.make_token" ) as make_token: make_token.return_value = "token" send_email_to_data_sender(user, language_code, type="created_user", request=request) emails = [mail.outbox.pop() for i in range(len(mail.outbox))] self.assertEqual(1, len(emails)) sent_email = emails[0] self.assertEqual("html", sent_email.content_subtype) self.assertEqual(settings.EMAIL_HOST_USER, sent_email.from_email) self.assertEqual(['*****@*****.**'], sent_email.to) self.assertEqual([settings.HNI_SUPPORT_EMAIL_ID], sent_email.bcc) ctx_dict = { 'domain': site.domain, 'uid': int_to_base36(user.id), 'user': user, 'token': "token", 'protocol': 'http', 'creator_user': request.user.first_name, 'site': site, } self.assertEqual( render_to_string( 'registration/created_user_email_subject_en.txt') % site.domain, sent_email.subject) self.assertEqual( render_to_string('registration/created_user_email_en.html', ctx_dict), sent_email.body)
def form_valid(self, form): """ If ResendActivationForm passed the validation, generate new token and send an e-mail. """ token_generator = PasswordResetTokenGenerator() users = LilyUser.objects.filter( email__iexact=form.cleaned_data['email']) # Get the current site or empty string try: current_site = Site.objects.get_current() except Site.DoesNotExist: current_site = '' for user in users: # Generate uidb36 and token for the activation link uidb36 = int_to_base36(user.pk) token = token_generator.make_token(user) # E-mail to the user send_templated_mail(template_name='activation', from_email=settings.DEFAULT_FROM_EMAIL, recipient_list=[form.cleaned_data['email']], context={ 'current_site': current_site, 'protocol': self.request.is_secure() and 'https' or 'http', 'user': user, 'uidb36': uidb36, 'token': token, }) # Show registration message messages.success( self.request, _('Reactivation successful. I\'ve sent you an email, please check it to activate your account.' )) # Redirect to success url return self.get_success_url()
def check_token(user_id, token): """ Check password-reset token correctness for User. @clmview_guest @param_post{user_id} User whose token should be checked @param_post{token} token to check @response None """ try: user = User.objects.get(id=user_id) except Exception: raise CLMException('user_get') if token_generator.check_token(user, int_to_base36(user_id) + u'-' + token): return raise CLMException('user_bad_token')
def _make_token_with_timestamp(self, timestamp): # timestamp is number of days since 2001-1-1. Converted to # base 36, this gives us a 3 digit string until about 2121 ts_b36 = int_to_base36(timestamp) hash = salted_hmac( 2, self._make_hash_value(timestamp), secret=self.secret, ).hexdigest()[::2] return "%s-%s" % (ts_b36, hash)
def form_valid(self, form): User = get_user_model() try: user = User.objects.get(email__iexact=form.cleaned_data["email"]) uid = int_to_base36(user.id) token = self.make_token(user) self.send_email(user, uid, token) except User.DoesNotExist: return self.form_invalid(form) response_kwargs = { "request": self.request, "template": self.template_name_sent, "context": self.get_context_data(form=form) } return self.response_class(**response_kwargs)
def test_password_reset_form_invalid(self, password1, password2, err_msg): """ Tests that password reset fail when providing bad passwords and error message is displayed to the user. """ user_email, _ = self._setup_user() # try to reset password, it should fail user = User.objects.get(email=user_email) token = default_token_generator.make_token(user) uidb36 = int_to_base36(user.id) # try to do a password reset with the same password as before resp = self.client.post('/password_reset_confirm/{0}-{1}/'.format(uidb36, token), { 'new_password1': password1, 'new_password2': password2, }, follow=True) self.assertPasswordResetError(resp, err_msg)
def forgot_password(self, user, token_generator=None): """ Sends 'Forgot Username or Password?' with their username and a link to the password reset form. """ from django.utils.http import int_to_base36 if token_generator is None: from django.contrib.auth.tokens import default_token_generator token_generator = default_token_generator token = token_generator.make_token(user) uid = int_to_base36(user.id) ctx = dict(PASSWORD_RESET_URL=absolute_uri( reverse("password_reset_confirm", kwargs={ "uidb36": uid, "token": token }))) self._sendmail('forgot-username-or-password', user.email, ctx)
def make_timed_token(user_id, minutes): """Make a URL-safe timed token that's valid for minutes minutes. The token is tied to a specific user to avoid frauds where a token is used to validate a different user than the one intended (i.e., to validate a user whose email the person doesn't control or by simple fishing for user id). """ secret = settings.SECRET_KEY rand_value = secrets.token_urlsafe(20) now = datetime.datetime.now().timestamp() soon = int_to_base36(int(now + 60 * minutes)) hmac = salted_hmac(soon, rand_value + str(user_id)).hexdigest()[:20] return '{rnd}|{u}|{t}|{h}'.format(rnd=rand_value, u=user_id, t=soon, h=hmac)
def test_cannot_change_mail_if_time_expired(self): regex_token = r"token=(([0-9a-z]*)-([0-9a-f]*))" new_mail = "*****@*****.**" send_confirmation_change_email(new_mail, str(self.person.pk)) match = re.search(regex_token, mail.outbox[0].body) ts = match.group(2) signature = match.group(3) token_expired = (int_to_base36( (base36_to_int(ts) - 8 * 24 * 60 * 60)) + "-" + signature) params = { "new_email": new_mail, "user": str(self.person.pk), "token": token_expired, } ulr_expired = reverse("confirm_change_mail") + "?" + urlencode(params) res = self.client.get(ulr_expired) self.assertContains(res, "Il semble que celui-ci est expiré.")
def send_email(self, email): User = get_user_model() protocol = getattr(settings, "DEFAULT_HTTP_PROTOCOL", "http") current_site = get_current_site(self.request) email_qs = EmailAddress.objects.filter(email__iexact=email) for user in User.objects.filter(pk__in=email_qs.values("user")): uid = int_to_base36(user.id) token = self.make_token(user) password_reset_url = "{0}://{1}{2}".format( protocol, current_site.domain, reverse("account_password_reset_token", kwargs=dict(uidb36=uid, token=token))) ctx = { "user": user, "current_site": current_site, "password_reset_url": password_reset_url, } hookset.send_password_reset_email([user.email], ctx)
def _make_token_with_timestamp(self, user, timestamp): # timestamp is number of days since 2001-1-1. Converted to # base.css 36, this gives us a 3 digit string until about 2121 ts_b36 = int_to_base36(timestamp) # By hashing on the internal state of the user and using state # that is sure to change (the password salt will change as soon as # the password is set, at least for current Django auth, and # last_login will also change), we produce a hash that will be # invalid as soon as it is used. # We limit the hash to 20 chars to keep URL short hash = salted_hmac( self.key_salt, self._make_hash_value(user, timestamp), secret=self.secret, ).hexdigest()[::2] return "%s-%s" % (ts_b36, hash)
def test_deki_email_multi_user(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Skip, if MindTouch API unavailable raise SkipTest() get_current.return_value.domain = 'testserver.com' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') r = self.client.post(reverse('users.pw_reset'), {'email': '*****@*****.**'}) eq_(302, r.status_code) eq_('http://testserver/en-US/users/pwresetsent', r['location']) eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Password reset') == 0 u = User.objects.get(username='******') assert mail.outbox[0].body.find('pwreset/%s' % int_to_base36(u.id)) > 0
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=configuration_helpers.get_value( 'email_from_address', settings.DEFAULT_FROM_EMAIL), request=None): """ Generates a one-use only link for resetting password and sends to the user. """ # This import is here because we are copying and modifying the .save from Django 1.4.5's # django.contrib.auth.forms.PasswordResetForm directly, which has this import in this place. from django.core.mail import send_mail for user in self.users_cache: if not domain_override: site_name = configuration_helpers.get_value( 'SITE_NAME', settings.SITE_NAME) else: site_name = domain_override context = { 'email': user.email, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME) } subject = loader.render_to_string(subject_template_name, context) # Email subject *must not* contain newlines subject = subject.replace('\n', '') email = loader.render_to_string(email_template_name, context) send_mail(subject, email, from_email, [user.email])
def save( self, email_template_name='registration/password_reset_email_user_list.html', **kwargs): """ Generates a one-use only link for resetting password and sends to the designated email. The email will contain links for resetting passwords for all accounts associated to the email. """ from django.core.mail import send_mail email_template_name = 'registration/password_reset_email_user_list.html' domain_override = kwargs.get('domain_override', False) use_https = kwargs.get('use_https', False) token_generator = kwargs.get('token_generator', default_token_generator) user_list = [] for user in self.users_cache: user_list.append({ 'uid': int_to_base36(user.id), 'user': user, 'token': token_generator.make_token(user), }) if not domain_override: site_name = get_setting('site', 'global', 'sitedisplayname') else: site_name = domain_override site_url = get_setting('site', 'global', 'siteurl') t = loader.get_template(email_template_name) c = { 'email': self.email, 'site_url': site_url, 'site_name': site_name, 'user_list': user_list, 'protocol': use_https and 'https' or 'http', } from_email = get_setting( 'site', 'global', 'siteemailnoreplyaddress') or settings.DEFAULT_FROM_EMAIL send_mail( _("Password reset on %s") % site_name, t.render(Context(c)), from_email, [user.email])
def registration(request): # if this is a POST request we need to process the form data if request.method == 'POST': # create a form instance and populate it with data from the request: user_form = UserRegistrationForm(request.POST) # check whether it's valid: if user_form.is_valid(): # Create new inactive user user = user_form.save() user.set_password(user_form.cleaned_data['password']) user.is_active = False user.save() # Save IP address profile = user.profile profile.ip_address = request.META.get('REMOTE_ADDR', None) profile.save() # Send email with activation key to the user current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain registration_token_generator = TokenGenerator( settings.REGISTRATION_TIMEOUT_DAYS) context = { 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.id), 'user': user, 'token': registration_token_generator.make_token(user), 'protocol': 'http', 'expire': settings.REGISTRATION_TIMEOUT_DAYS, } subject = u'Registration confirmation on %s' % site_name message = render_to_string('registration/registration_email.txt', context) user.email_user(subject, message) return HttpResponseRedirect(reverse('registration_done')) else: user_form = UserRegistrationForm() return {'user_form': user_form}
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.html', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ from django.core.mail import send_mail for user in self.users_cache: obj, created = User.objects.get_or_create(username=user.username, email=user.email, password=user.password) if created: obj.is_active = True obj.last_login = timezone.now() obj.save() if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': obj.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(obj.pk), 'username': obj.username.encode('utf-8'), 'first_name': obj.first_name.encode('utf-8'), 'token': token_generator.make_token(obj), 'protocol': use_https and 'https' or 'http', } subject = loader.render_to_string(subject_template_name, c) subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) send_mail(subject, email, from_email, [obj.email])
def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': int_to_base36(user.pk), 'user': user, 'token': token_generator.make_token(user), 'protocol': use_https and 'https' or 'http', } subject = loader.render_to_string( 'messages/emails/password_reset_subject.txt', c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) text_content = loader.render_to_string( 'messages/emails/password_reset.txt', c) if not settings.DEBUG: html_content = loader.render_to_string( 'messages/emails/password_reset.html', c) else: html_content = None msg = EmailMultiAlternatives(subject, text_content, from_email, [user.email]) if html_content: msg.attach_alternative(html_content, "text/html") msg.send()
def notification_register(self): # get setting appearance from academy.apps.offices import utils sett = utils.get_settings(serializer=True) data = { 'token': default_token_generator.make_token(self), 'uid': int_to_base36(self.id), 'host': settings.HOST, 'user': self, 'email_title': 'Aktivasi Akun' } data.update(sett) kwargs = construct_email_args( recipients=[self.email], subject='Aktivasi Akun', content=render_to_string('emails/register.html', context=data), priority=PRIORITY.now) django_rq.enqueue(mail.send, **kwargs)
def decode(code, max_age=3 * 86400): """ Decodes the code from the registration link and returns a tuple consisting of the verified email address and the associated user instance or ``None`` if no user was passed to ``send_registration_mail`` This method raises ``InvalidCode`` exceptions containing an translated message what went wrong suitable for presenting directly to the user. """ try: data = get_signer().unsign(code, max_age=max_age) except signing.SignatureExpired: raise InvalidCode( _("The link is expired. Please request another registration link.") ) except signing.BadSignature: raise InvalidCode( _("Unable to verify the signature. Please request a new" " registration link.")) parts = data.rsplit(":", 2) if len(parts) != 3: raise InvalidCode( _("Something went wrong while decoding the" " registration request. Please try again.")) email, uid, timestamp = parts if uid and timestamp: try: user = User.objects.get(pk=uid) except (User.DoesNotExist, TypeError, ValueError): raise InvalidCode( _("Something went wrong while decoding the" " registration request. Please try again.")) if timestamp != int_to_base36(get_last_login_timestamp(user)): raise InvalidCode(_("The link has already been used.")) else: user = None return email, user
def test_check_token_success_without_flag(self): dashboard = factories.Dashboard( public={'all': False, 'org': False, 'url': True}) timestamp = self.token_generator._num_days( self.token_generator._today()) test_hash = ( six.text_type(dashboard.pk) + dashboard.dashboard_uuid.__str__() + six.text_type(timestamp) ) ts_b36 = int_to_base36(timestamp) hash = salted_hmac(self.token_generator.key_salt, test_hash).hexdigest()[::2] final_hash = '{}-{}'.format(ts_b36, hash) is_valid = self.token_generator.check_token(dashboard, final_hash) self.assertTrue(is_valid)
def signup(request): """Signs up new users""" if request.method == 'POST': mail = request.POST['email'] usercheck = accounts.UserChecks(request.user) person = usercheck.get_person_by_email(mail) if person is False: msg = """Ditt email kunde inte hittas på eventor. Var god och använd email addressen som du använder på idrottonline.""" return signup_error(request, msg) elif usercheck.account_exists_and_activated(mail): msg = """Ditt email har redan ett konto. Var god och försök att logga in istället.""" return signup_error(request, msg) else: username = request.POST['username'] password = request.POST['password'] errmsg = usercheck.check_account_details(username, password) if errmsg.values() != [None, None]: if errmsg['password'] is not None: msg = errmsg['password'] if errmsg['username'] is not None: msg = errmsg['username'] return signup_error(request, msg) # check there is not already a user account, else create account # user accounts can lie around unactivated user = usercheck.account_exists(mail) if user is False: user = accounts.create_user_account(mail, password, person, username) # send activation mail current_site = get_current_site(request) uidb36 = int_to_base36(user.pk) token = default_token_generator.make_token(user) link = '/'.join(['http:/', current_site.domain, 'accounts/activate/{0}-{1}'.format(uidb36,token)]) accounts.send_new_account_mail(user, link) # return a mail sent template return render(request, 'registration/signup_successful.html') else: return render(request, 'registration/signup.html')
def test_wrong_token(self): """ Test that a 403 forbidden is raised with an incorrect token. """ user = UserFactory(forumuser_id=self.forum_user.pk, is_active=False) user2 = UserFactory(forumuser_id=self.forum_user.pk, is_active=False) token = activation_token_generator.make_token(user2) uidb36 = int_to_base36(user.id) url = reverse('users:activate', kwargs={ 'token': token, 'uidb36': uidb36 }) self.assertIsNotNone(url) response = self.client.get(url) self.assertEqual(response.status_code, 403)
def testInviteUser(self): # Try to render the form. response = self.client.get("/admin/auth/user/invite/") self.assertEqual(response.status_code, 200) # Invite a user. response = self.client.post( "/admin/auth/user/invite/", { "username": "******", "email": "*****@*****.**", "first_name": "Bar", "last_name": "Foo", }) self.assertEqual(response.status_code, 302) self.assertEqual(response["Location"], "http://testserver/admin/auth/user/") self.assertEqual(len(mail.outbox), 1) user = User.objects.get(username="******") self.assertTrue(user.is_staff) self.assertFalse(user.is_active) # Log out from the admin system. self.client.logout() # Try to complete the signup. confirmation_url = reverse( "admin:auth_user_invite_confirm", kwargs={ "uidb36": int_to_base36(user.id), "token": default_token_generator.make_token(user), }) response = self.client.post(confirmation_url, { "password1": "password", "password2": "password", }) self.assertEqual(response.status_code, 302) self.assertEqual(response["Location"], "http://testserver/admin/") user = User.objects.get(username=user.username) self.assertTrue(user.is_active) # Has the link now expired? response = self.client.post(confirmation_url, { "password1": "password", "password2": "password", }) self.assertEqual(response.status_code, 200) # 200 status means an error message.
def _make_token_with_timestamp(self, user, timestamp): # timestamp is number of days since 2001-1-1. Converted to # base 36, this gives us a 3 digit string until about 2121 ts_b36 = int_to_base36(timestamp) # By hashing on the internal state of the user and using state # that is sure to change (the password salt will change as soon as # the password is set, at least for current Django auth, and # last_login will also change), we produce a hash that will be # invalid as soon as it is used. # We limit the hash to 20 chars to keep URL short import hashlib import datetime ctime = datetime.datetime.fromtimestamp(user.ctime / 1000000) hash = hashlib.sha1(settings.SECRET_KEY + unicode(user.id) + ctime.strftime('%Y-%m-%d %H:%M:%S') + unicode(timestamp)).hexdigest()[::2] return "%s-%s" % (ts_b36, hash)
def forget(request): if request.method == 'POST': email = request.POST.get('email') try: user = models.User.objects.get(email=email) except: return render(request, 'main/forget.html', {'error': 'ایمیل شما معتبر نمیباشد'}) generator = PasswordResetTokenGenerator() token = generator.make_token(user) uidb36 = int_to_base36(user.pk) uri = request.build_absolute_uri(reverse('reset_password', kwargs={'uidb36': uidb36, 'token': token})) send_mail(summary='فراموشی رمز عبور', content=''' برای دریافت رمز عبور جدید روی <a href="%s">این لینک </a> کلیک کنید. </br> در صورتی که شما درخواست فراموشی رمز عبور ندادهاید میتوانید این ایمیل را نادیده بگیرید.''' % uri, to=[email]) return render(request, 'main/forget.html', {'success': 'ایمیل تایید فراموشی به شما ارسال شد'}) else: return render(request, 'main/forget.html', {})
def send_registration_mail(email, request, user=None, **kwargs): """ Sends the registration mail * ``email``: The email address where the registration link should be sent to. * ``request``: A HTTP request instance, used to construct the complete URL (including protocol and domain) for the registration link. * ``user``: Optional user instance. If the user exists already and you just want to send a link where the user can choose his/her password. The mail is rendered using the following two templates: * ``registration/email_registration_email.txt``: The first line of this template will be the subject, the third to the last line the body of the email. * ``registration/email_registration_email.html``: The body of the HTML version of the mail. This template is **NOT** available by default and is not required either. """ code = [email, '', ''] if user: code[1] = str(user.id) code[2] = int_to_base36(get_last_login_timestamp(user)) url = request.build_absolute_uri( reverse('email_registration_confirm', kwargs={ 'code': get_signer().sign(u':'.join(code)), })) contextList = { 'url': url, } if settings.EMAIL_CONTEXT: contextList.update(settings.EMAIL_CONTEXT) render_to_mail('registration/email_registration_email', context=contextList, to=[email], **kwargs).send()
def _make_token_with_timestamp(self, user, timestamp): # timestamp is number of days since 2001-1-1. Converted to # base 36, this gives us a 3 digit string until about 2121 ts_b36 = int_to_base36(timestamp) # By hashing on the internal state of the user and using state # that is sure to change (when user signup the is_active change), # we produce a hash that will be invalid as soon as it is used. # We limit the hash to 20 chars to keep URL short key_salt = "myuser.tokens.SignupTokenGenerator" # Ensure results are consistent across DB backends signup_timestamp = '' if user.date_joined is None else user.date_joined.replace( microsecond=0, tzinfo=None) value = (six.text_type(user.pk) + user.password + six.text_type(signup_timestamp) + six.text_type(timestamp)) hash = salted_hmac(key_salt, value).hexdigest()[::2] return "%s-%s" % (ts_b36, hash)
def _pack_passwordreset(self, email): user = User.objects.get(email__iexact=email) domain = unicode(self.get_site().domain) subject = settings.EMAIL_PASSWD_RESET_SUBJECT current_site = self.get_site() url = u'%s://%s%s' % ( getattr(settings, 'DEFAULT_HTTP_PROTOCOL', 'http'), unicode(unicode(current_site.domain)), reverse('acct_password_reset_token', args=[int_to_base36(user.id), self.related_object.temp_key]) ) context = {'url': url} text, html = self.render(context, domain, settings.EMAIL_PWD_RESET_MSG, settings.EMAIL_PWD_RESET_HTML) return subject, text, html