Mandate email validation for free accounts. Be sure to set EMAIL_VALIDATION_CUTOFF_DATE before deploy

This commit is contained in:
Kyle Drake 2016-05-13 16:48:29 -04:00
parent cef1611003
commit a2a6a40438
19 changed files with 178 additions and 27 deletions

2
app.rb
View file

@ -29,6 +29,8 @@ before do
content_type :json content_type :json
elsif request.path.match /^\/webhooks\// elsif request.path.match /^\/webhooks\//
# Skips the CSRF check for stripe web hooks # Skips the CSRF check for stripe web hooks
elsif email_not_validated? && !(request.path =~ /^\/site\/.+\/confirm_email|^\/settings\/change_email|^\/signout|^\/welcome|^\/plan/)
redirect "/site/#{current_site.username}/confirm_email"
else else
content_type :html, 'charset' => 'utf-8' content_type :html, 'charset' => 'utf-8'
redirect '/' if request.post? && !csrf_safe? redirect '/' if request.post? && !csrf_safe?

View file

@ -138,6 +138,7 @@ end
def require_api_credentials def require_api_credentials
if !request.env['HTTP_AUTHORIZATION'].nil? if !request.env['HTTP_AUTHORIZATION'].nil?
init_api_credentials init_api_credentials
api_error(403, 'email_not_validated', 'you need to validate your email address before using the API') if email_not_validated?
else else
api_error_invalid_auth api_error_invalid_auth
end end

View file

@ -280,9 +280,15 @@ end
post '/settings/change_email' do post '/settings/change_email' do
require_login require_login
if params[:from_confirm]
redirect_url = "/site/#{parent_site.username}/confirm_email"
else
redirect_url = '/settings#email'
end
if params[:email] == parent_site.email if params[:email] == parent_site.email
flash[:error] = 'You are already using this email address for this account.' flash[:error] = 'You are already using this email address for this account.'
redirect '/settings#email' redirect redirect_url
end end
parent_site.email = params[:email] parent_site.email = params[:email]
@ -292,12 +298,17 @@ post '/settings/change_email' do
if parent_site.valid? if parent_site.valid?
parent_site.save_changes parent_site.save_changes
send_confirmation_email send_confirmation_email
flash[:success] = 'Successfully changed email. We have sent a confirmation email, please use it to confirm your email address.' if !parent_site.supporter?
redirect '/settings#email' session[:fromsettings] = true
redirect "/site/#{parent_site.email}/confirm_email"
else
flash[:success] = 'Email address changed.'
redirect '/settings#email'
end
end end
flash[:error] = parent_site.errors.first.last.first flash[:error] = parent_site.errors.first.last.first
redirect '/settings#email' redirect redirect_url
end end
post '/settings/change_email_notification' do post '/settings/change_email_notification' do

View file

@ -172,8 +172,23 @@ post '/site/create_directory' do
end end
get '/site/:username/confirm_email/:token' do get '/site/:username/confirm_email/:token' do
if current_site && current_site.email_confirmed
return erb(:'site_email_confirmed')
end
site = Site[username: params[:username]] site = Site[username: params[:username]]
if !site.nil? && site.email_confirmation_token == params[:token]
if site.nil?
return erb(:'site_email_not_confirmed')
end
if site.email_confirmed
return erb(:'site_email_confirmed')
end
if site.email_confirmation_token == params[:token]
site.email_confirmation_token = nil
site.email_confirmation_count = 0
site.email_confirmed = true site.email_confirmed = true
site.save_changes site.save_changes
@ -183,6 +198,47 @@ get '/site/:username/confirm_email/:token' do
end end
end end
get '/site/:username/confirm_email' do
require_login
@fromsettings = session[:fromsettings]
redirect '/' if current_site.username != params[:username] || !current_site.parent? || current_site.email_confirmed
erb :'site/confirm_email'
end
post '/site/:username/confirm_email' do
require_login
redirect '/' if current_site.username != params[:username] || !current_site.parent? || current_site.email_confirmed
# Update email, resend token
if params[:email]
send_confirmation_email @site
end
if params[:token].blank?
flash[:error] = 'You must enter a valid token.'
redirect "/site/#{current_site.username}/confirm_email"
end
if current_site.email_confirmation_token == params[:token]
current_site.email_confirmation_token = nil
current_site.email_confirmation_count = 0
current_site.email_confirmed = true
current_site.save_changes
if session[:fromsettings]
session[:fromsettings] = nil
flash[:success] = 'Email address changed.'
redirect '/settings#email'
end
redirect '/'
else
flash[:error] = 'You must enter a valid token.'
redirect "/site/#{current_site.username}/confirm_email"
end
end
post '/site/:username/report' do |username| post '/site/:username/report' do |username|
site = Site[username: username] site = Site[username: username]

View file

@ -72,12 +72,19 @@ def encoding_fix(file)
end end
def send_confirmation_email(site=current_site) def send_confirmation_email(site=current_site)
if site.email_confirmation_count > Site::MAXIMUM_EMAIL_CONFIRMATIONS
flash[:error] = 'You sent too many email confirmation requests, cannot continue.'
redirect request.referrer
end
DB['UPDATE sites set email_confirmation_count=email_confirmation_count+1 WHERE id=?', site.id].first
EmailWorker.perform_async({ EmailWorker.perform_async({
from: 'web@neocities.org', from: 'web@neocities.org',
reply_to: 'contact@neocities.org', reply_to: 'contact@neocities.org',
to: site.email, to: site.email,
subject: "[Neocities] Confirm your email address", subject: "[Neocities] Confirm your email address",
body: Tilt.new('./views/templates/email_confirm.erb', pretty: true).render(self, site: site) body: Tilt.new('./views/templates/email/confirm.erb', pretty: true).render(self, site: site)
}) })
end end
@ -116,3 +123,7 @@ end
def dont_browser_cache def dont_browser_cache
@dont_browser_cache = true @dont_browser_cache = true
end end
def email_not_validated?
current_site && current_site.parent? && !current_site.is_education && !current_site.email_confirmed && !current_site.supporter? && Site::EMAIL_VALIDATION_CUTOFF_DATE < Time.now
end

View file

@ -121,6 +121,8 @@ class Site < Sequel::Model
maximum_site_files: 2000 maximum_site_files: 2000
) )
EMAIL_VALIDATION_CUTOFF_DATE = Time.now - 1
def self.newsletter_sites def self.newsletter_sites
Site.select(:email). Site.select(:email).
exclude(email: 'nil').exclude(is_banned: true). exclude(email: 'nil').exclude(is_banned: true).
@ -160,6 +162,8 @@ class Site < Sequel::Model
EMAIL_BLAST_MAXIMUM_PER_DAY = 1000 EMAIL_BLAST_MAXIMUM_PER_DAY = 1000
end end
MAXIMUM_EMAIL_CONFIRMATIONS = 20
many_to_many :tags many_to_many :tags
one_to_many :profile_comments one_to_many :profile_comments

0
public/fonts/dlfonts.sh Executable file → Normal file
View file

0
public/fonts/ocra-webfont.eot Executable file → Normal file
View file

0
public/fonts/ocra-webfont.svg Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

0
public/fonts/ocra-webfont.ttf Executable file → Normal file
View file

0
public/fonts/ocra-webfont.woff Executable file → Normal file
View file

View file

@ -16,7 +16,14 @@ describe 'site/settings' do
@new_email = "#{SecureRandom.uuid.gsub('-', '')}@example.com" @new_email = "#{SecureRandom.uuid.gsub('-', '')}@example.com"
fill_in 'email', with: @new_email fill_in 'email', with: @new_email
click_button 'Change Email' click_button 'Change Email'
page.must_have_content /successfully changed email/i
page.must_have_content /enter the confirmation code here/
fill_in 'token', with: @site.reload.email_confirmation_token
click_button 'Confirm Email'
page.must_have_content /Email address changed/i
@site.reload @site.reload
@site.email.must_equal @new_email @site.email.must_equal @new_email
EmailWorker.jobs.length.must_equal 1 EmailWorker.jobs.length.must_equal 1

View file

@ -345,13 +345,11 @@ describe 'delete' do
owned_site = Fabricate :site, parent_site_id: @site.id owned_site = Fabricate :site, parent_site_id: @site.id
visit "/settings/#{owned_site.username}#delete" visit "/settings/#{owned_site.username}#delete"
fill_in 'confirm_username', with: owned_site.username fill_in 'confirm_username', with: owned_site.username
fill_in 'deleted_reason', with: 'got bored with it'
click_button 'Delete Site' click_button 'Delete Site'
@site.reload @site.reload
owned_site.reload owned_site.reload
owned_site.is_deleted.must_equal true owned_site.is_deleted.must_equal true
owned_site.deleted_reason.must_equal 'got bored with it'
@site.is_deleted.must_equal false @site.is_deleted.must_equal false
page.current_path.must_equal "/settings" page.current_path.must_equal "/settings"

View file

@ -54,6 +54,12 @@ describe 'signup' do
click_signup_button click_signup_button
site_created? site_created?
click_link 'Continue'
page.must_have_content /almost ready!/
fill_in 'token', with: Site[username: @site[:username]].email_confirmation_token
click_button 'Confirm Email'
page.must_have_content /Thanks for joining the Neocities community/
index_file_path = File.join Site::SITE_FILES_ROOT, @site[:username], 'index.html' index_file_path = File.join Site::SITE_FILES_ROOT, @site[:username], 'index.html'
File.exist?(index_file_path).must_equal true File.exist?(index_file_path).must_equal true

View file

@ -1,5 +1,6 @@
Fabricator(:site) do Fabricator(:site) do
username { SecureRandom.hex } username { SecureRandom.hex }
password { 'abcde' } password { 'abcde' }
email { SecureRandom.uuid.gsub('-', '')+'@example.com' } email { SecureRandom.uuid.gsub('-', '')+'@example.com' }
end email_confirmed { true }
end

View file

@ -15,5 +15,13 @@
<a href="/tutorials">Learn</a> <a href="/tutorials">Learn</a>
</li> </li>
<li> <li>
<a href="/plan">Support Us<i class="fa fa-heart"><i class="fa fa-heart"></i></i></a> <a href="/plan">
</li> <% if signed_in? %>
<% unless current_site.supporter? %>
Upgrade to Supporter<i class="fa fa-heart"><i class="fa fa-heart"></i></i>
<% end %>
<% else %>
Support Us<i class="fa fa-heart"><i class="fa fa-heart"></i></i>
<% end %>
</a>
</li>

View file

@ -3,31 +3,24 @@
<h1 class="beta txt-Center">The Neocities Team</h1> <h1 class="beta txt-Center">The Neocities Team</h1>
<div class="row txt-Center"> <div class="row txt-Center">
<div class="col col-33"> <div class="col col-50">
<a href="https://kyledrake.neocities.org" title="Visit Kyle's Website"> <a href="https://kyledrake.neocities.org" title="Visit Kyle's Website">
<img src="https://0.gravatar.com/avatar/62a43048a3c2c688654274abdc0ecb9c?d=https%3A%2F%2Fidenticons.github.com%2Ffde07ba82b25f95afa9d080819f95717.png&amp;r=x&amp;s=440" alt="kyle drake" class="pic-Rounded" /> <img src="https://0.gravatar.com/avatar/62a43048a3c2c688654274abdc0ecb9c?d=https%3A%2F%2Fidenticons.github.com%2Ffde07ba82b25f95afa9d080819f95717.png&amp;r=x&amp;s=440" alt="kyle drake" class="pic-Rounded" />
</a> </a>
<br /> <br />
<a href="https://kyledrake.neocities.org" title="Kyle Drake" class="eps">Kyle Drake</a> <a href="https://kyledrake.neocities.org" title="Kyle Drake" class="eps">Kyle Drake</a>
</div> </div>
<div class="col col-33"> <div class="col col-50">
<a href="https://victoria.neocities.org" title="Visit Victoria's Website"> <a href="https://victoria.neocities.org" title="Visit Victoria's Website">
<img src="https://1.gravatar.com/avatar/2b577f8b3e5ab79bc927ed5185c0eae0?d=https%3A%2F%2Fidenticons.github.com%2Fe03006819f4a835afa237716f6701c95.png&amp;r=x&amp;s=440" alt="Victoria Wang" class="pic-Rounded" /> <img src="https://1.gravatar.com/avatar/2b577f8b3e5ab79bc927ed5185c0eae0?d=https%3A%2F%2Fidenticons.github.com%2Fe03006819f4a835afa237716f6701c95.png&amp;r=x&amp;s=440" alt="Victoria Wang" class="pic-Rounded" />
</a> </a>
<br /> <br />
<a href="https://victoria.neocities.org" title="Visit Victoria's Website" class="eps">Victoria Wang</a> <a href="https://victoria.neocities.org" title="Visit Victoria's Website" class="eps">Victoria Wang</a>
</div> </div>
<div class="col col-33">
<a href="http://scottohara.neocities.org" title="Visit Scott's Website">
<img src="https://0.gravatar.com/avatar/6ade16e6184b3efb573ee91255ff7abe?d=https%3A%2F%2Fidenticons.github.com%2Fa6362986538cdcb93a8b04f6c3f66b5e.png&amp;r=x&amp;s=440" alt="Scott O'Hara" class="pic-Rounded" />
</a>
<br />
<a href="http://scottohara.neocities.org" title="Visit Scott's Website" class="eps">Scott O'Hara</a>
</div>
</div> </div>
</section> </section>
<hr /> <hr />
<section> <section>
<h2 class="txt-Center">Follow us on <a href="https://twitter.com/neocitiesweb">Twitter</a> or <a href="https://www.facebook.com/neocities">Facebook</a></h2> <h2 class="txt-Center">Follow us on <a href="https://twitter.com/neocitiesweb">Twitter</a> or <a href="https://www.facebook.com/neocities">Facebook</a></h2>
</section> </section>

View file

@ -0,0 +1,51 @@
<section class="section plans welcome">
<h2>Check your Email</h2>
<div class="txt-Center"><img src="/img/fatcat.png" width="70px"></div>
<h3 class="subtitle">
<% if !@fromsettings %>
You're almost ready!<br>
<% end %>
We sent an email to <strong><%= current_site.email %></strong> to make sure it's correct.<br>Please check your email, enter the confirmation code here, and you're all set.
</h3>
<div class="row">
<div class="col col-100 txt-Center" style="margin-top: 10px;">
<% if flash[:success] %>
<div class="alert alert-block alert-success" style="margin-top: 20px">
<%== flash[:success] %>
</div>
<% end %>
<% if flash[:error] %>
<div class="alert alert-block alert-error" style="margin-top: 20px">
<%== flash[:error] %>
</div>
<% end %>
<form method="POST" action="/site/<%= current_site.username %>/confirm_email" class="content">
<%== csrf_token_input_html %>
<fieldset>
<label for="token">Email Confirmation Token</label>
<input name="token" type="text" class="input-Area" autofill="off" autocapitalize="off" autocorrect="off" value="<%= flash[:token] %>" style="width: 290px">
</fieldset>
<input class="btn-Action" type="submit" value="Confirm Email">
</form>
<h2 style="margin-top: 30px">Wrong email?</h2>
<h3 class="subtitle">If you entered the wrong email address by mistake:</h3>
<form method="POST" action="/settings/change_email" class="content">
<%== csrf_token_input_html %>
<input type="hidden" name="from_confirm" value="1">
<fieldset>
<input name="email" type="text" class="input-Area" autofill="off" autocapitalize="off" autocorrect="off" value="<%= current_site.email %>" style="width: 290px">
</fieldset>
<input class="btn-Action" type="submit" value="Update Email Address">
</form>
</div>
</div>
</section>

View file

@ -2,11 +2,13 @@ Hello <%= site.username %>,
Please confirm your email address for Neocities! Please confirm your email address for Neocities!
You can confirm your email address using the link below: Your email confirmation code is: <%= site.email_confirmation_token %>
You can also confirm your email address using the link below:
https://neocities.org/site/<%= site.username %>/confirm_email/<%= site.email_confirmation_token %> https://neocities.org/site/<%= site.username %>/confirm_email/<%= site.email_confirmation_token %>
Thank you! Thank you!
- The Neocities Team - The Neocities Team