Skip to content

Commit

Permalink
support unicode emails.
Browse files Browse the repository at this point in the history
just using u'unicode' in all the arbitrary strings
built by normal string building, everything will be
handled nicely by flask.

flask already gives us all parameters and form values
in unicode objects, and does the nice handling trans-
parently in render_template, so not many changes are
needed.
  • Loading branch information
fiatjaf committed Sep 24, 2016
1 parent cd3abb1 commit 7274b84
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 90 deletions.
2 changes: 1 addition & 1 deletion formspree/forms/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from formspree import settings

HASH = lambda x, y: hashlib.md5(x+y+settings.NONCE_SECRET).hexdigest()
HASH = lambda x, y: hashlib.md5(x.encode('utf-8')+y.encode('utf-8')+settings.NONCE_SECRET).hexdigest()
EXCLUDE_KEYS = {'_gotcha', '_next', '_subject', '_cc', '_format'}
MONTHLY_COUNTER_KEY = 'monthly_{form_id}_{month}'.format
HASHIDS_CODEC = hashids.Hashids(alphabet='abcdefghijklmnopqrstuvwxyz',
Expand Down
38 changes: 24 additions & 14 deletions formspree/forms/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ def send(email_or_string):
if request_wants_json():
return jsonerror(400, {'error': "Can't send an empty form"})
else:
return render_template('error.html',
title='Can\'t send an empty form',
text=str('<p>Make sure you have placed the <a href="http://www.w3schools.com/tags/att_input_name.asp" target="_blank"><code>"name"</code> attribute</a> in all your form elements. Also, to prevent empty form submissions, take a look at the <a href="http://www.w3schools.com/tags/att_input_required.asp" target="_blank"><code>"required"</code> property</a>.</p><p>This error also happens when you have an <code>"enctype"</code> attribute set in your <code>&lt;form&gt;</code>, so make sure you don\'t.</p><p><a href="%s">Return to form</a></p>' % request.referrer)), 400
return render_template(
'error.html',
title='Can\'t send an empty form',
text=u'<p>Make sure you have placed the <a href="http://www.w3schools.com/tags/att_input_name.asp" target="_blank"><code>"name"</code> attribute</a> in all your form elements. Also, to prevent empty form submissions, take a look at the <a href="http://www.w3schools.com/tags/att_input_required.asp" target="_blank"><code>"required"</code> property</a>.</p><p>This error also happens when you have an <code>"enctype"</code> attribute set in your <code>&lt;form&gt;</code>, so make sure you don\'t.</p><p><a href="{}">Return to form</a></p>'.format(request.referrer)
), 400
elif status['code'] == Form.STATUS_CONFIRMATION_SENT or \
status['code'] == Form.STATUS_CONFIRMATION_DUPLICATED:

Expand All @@ -170,15 +172,21 @@ def send(email_or_string):
if request_wants_json():
return jsonerror(500, {'error': "_replyto or email field has not been sent correctly"})
else:
return render_template('error.html', title='Invalid email address', text='You entered <span class="code">{address}</span>. That is an invalid email address. Please correct the form and try to submit again <a href="{back}">here</a>.<p style="font-size: small">This could also be a problem with the form. For example, there could be two fields with <span class="code">_replyto</span> or <span class="code">email</span> name attribute. If you suspect the form is broken, please contact the form owner and ask them to investigate</p>'''.format(address=status['address'], back=status['referrer'])), 400
return render_template(
'error.html',
title='Invalid email address',
text=u'You entered <span class="code">{address}</span>. That is an invalid email address. Please correct the form and try to submit again <a href="{back}">here</a>.<p style="font-size: small">This could also be a problem with the form. For example, there could be two fields with <span class="code">_replyto</span> or <span class="code">email</span> name attribute. If you suspect the form is broken, please contact the form owner and ask them to investigate</p>'''.format(address=status['address'], back=status['referrer'])
), 400

# error fallback -- shouldn't happen
if request_wants_json():
return jsonerror(500, {'error': "Unable to send email"})
else:
return render_template('error.html',
title='Unable to send email',
text='Unable to send email. If you can, please send the link to your form and the error information to <b>{email}</b>. And send them the following: <p><pre><code>{message}</code></pre></p>'.format(message=json.dumps(status), email=settings.CONTACT_EMAIL)), 500
return render_template(
'error.html',
title='Unable to send email',
text=u'Unable to send email. If you can, please send the link to your form and the error information to <b>{email}</b>. And send them the following: <p><pre><code>{message}</code></pre></p>'.format(message=json.dumps(status), email=settings.CONTACT_EMAIL)
), 500


def resend_confirmation(email):
Expand Down Expand Up @@ -366,7 +374,7 @@ def create_form():
if request_wants_json():
return jsonerror(400, {'error': "The provided email address is not valid."})
else:
flash('The provided email address is not valid.', 'error')
flash(u'The provided email address is not valid.', 'error')
return redirect(url_for('dashboard'))

g.log.info('Creating a new form from the dashboard.')
Expand All @@ -383,7 +391,9 @@ def create_form():
form.host = remove_www(referrer_to_path(urljoin(url, '/'))[:-1])
form.sitewide = True
else:
return jsonerror(403, {'error': "Couldn't verify the file at %s." % url})
return jsonerror(403, {
'error': u"Couldn't verify the file at {}.".format(url)
})

DB.session.add(form)
DB.session.commit()
Expand Down Expand Up @@ -411,7 +421,7 @@ def create_form():
'confirmed': form.confirmed
})
else:
flash('Your new form endpoint was created!', 'success')
flash(u'Your new form endpoint was created!', 'success')
return redirect(url_for('dashboard', new=form.hashid) + '#form-' + form.hashid)


Expand Down Expand Up @@ -523,9 +533,9 @@ def form_toggle(hashid):
DB.session.add(form)
DB.session.commit()
if form.disabled:
flash('Form successfully disabled', 'success')
flash(u'Form successfully disabled', 'success')
else:
flash('Form successfully enabled', 'success')
flash(u'Form successfully enabled', 'success')
return redirect(url_for('dashboard'))


Expand Down Expand Up @@ -555,7 +565,7 @@ def form_deletion(hashid):
DB.session.delete(submission)
DB.session.delete(form)
DB.session.commit()
flash('Form successfully deleted', 'success')
flash(u'Form successfully deleted', 'success')
return redirect(url_for('dashboard'))


Expand Down Expand Up @@ -590,5 +600,5 @@ def submission_deletion(hashid, submissionid):
form.counter -= 1
DB.session.add(form)
DB.session.commit()
flash('Submission successfully deleted', 'success')
flash(u'Submission successfully deleted', 'success')
return redirect(url_for('form-submissions', hashid=hashid))
4 changes: 2 additions & 2 deletions formspree/templates/layouts/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
<div class="row">
<div class="container">
<div class="col-1-1">
{% for category, message in messages %}
{% for category, flashed in messages %}
<div class="alert-box {{ category }} banner">
{{ message|safe }}
{{ flashed|safe }}
</div>
{% endfor %}
</div>
Expand Down
24 changes: 17 additions & 7 deletions formspree/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,17 @@ def send_confirmation(addr, user_id):
addr = addr.lower().strip()
if not IS_VALID_EMAIL(addr):
g.log.info('Failed. Invalid address.')
raise ValueError('Cannot send confirmation. %s is not a valid email.' % addr)

message = 'email={email}&user_id={user_id}'.format(email=addr, user_id=user_id)
digest = hmac.new(settings.NONCE_SECRET, message, hashlib.sha256).hexdigest()
link = url_for('confirm-account-email', digest=digest, email=addr, _external=True)
raise ValueError(u'Cannot send confirmation. '
'{} is not a valid email.'.format(addr))

message = u'email={email}&user_id={user_id}'.format(
email=addr,
user_id=user_id)
digest = hmac.new(
settings.NONCE_SECRET, message.encode('utf-8'), hashlib.sha256
).hexdigest()
link = url_for('confirm-account-email',
digest=digest, email=addr, _external=True)
res = send_email(
to=addr,
subject='Confirm email for your account at %s' % settings.SERVICE_NAME,
Expand All @@ -134,8 +140,12 @@ def send_confirmation(addr, user_id):
@classmethod
def create_with_digest(cls, addr, user_id, digest):
addr = addr.lower()
message = 'email={email}&user_id={user_id}'.format(email=addr, user_id=user_id)
what_should_be = hmac.new(settings.NONCE_SECRET, message, hashlib.sha256).hexdigest()
message = u'email={email}&user_id={user_id}'.format(
email=addr,
user_id=user_id)
what_should_be = hmac.new(
settings.NONCE_SECRET, message.encode('utf-8'), hashlib.sha256
).hexdigest()
if digest == what_should_be:
return cls(address=addr, owner_id=user_id)
else:
Expand Down
Loading

0 comments on commit 7274b84

Please sign in to comment.