From a2a6a40438ce1097209558320eb78cb0d5bfff5f Mon Sep 17 00:00:00 2001 From: Kyle Drake Date: Fri, 13 May 2016 16:48:29 -0400 Subject: [PATCH] Mandate email validation for free accounts. Be sure to set EMAIL_VALIDATION_CUTOFF_DATE before deploy --- app.rb | 2 + app/api.rb | 1 + app/settings.rb | 19 ++++-- app/site.rb | 58 +++++++++++++++++- app_helpers.rb | 13 +++- models/site.rb | 4 ++ public/fonts/dlfonts.sh | 0 public/fonts/ocra-webfont.eot | Bin public/fonts/ocra-webfont.svg | 0 public/fonts/ocra-webfont.ttf | Bin public/fonts/ocra-webfont.woff | Bin tests/acceptance/settings/account_tests.rb | 9 ++- tests/acceptance/settings/site_tests.rb | 2 - tests/acceptance/signup_tests.rb | 6 ++ tests/fabricators/site_fabricator.rb | 9 +-- views/_header_links.erb | 12 +++- views/_team.erb | 13 +--- views/site/confirm_email.erb | 51 +++++++++++++++ .../{email_confirm.erb => email/confirm.erb} | 6 +- 19 files changed, 178 insertions(+), 27 deletions(-) mode change 100755 => 100644 public/fonts/dlfonts.sh mode change 100755 => 100644 public/fonts/ocra-webfont.eot mode change 100755 => 100644 public/fonts/ocra-webfont.svg mode change 100755 => 100644 public/fonts/ocra-webfont.ttf mode change 100755 => 100644 public/fonts/ocra-webfont.woff create mode 100644 views/site/confirm_email.erb rename views/templates/{email_confirm.erb => email/confirm.erb} (55%) diff --git a/app.rb b/app.rb index 238e02b7..f1298dc6 100644 --- a/app.rb +++ b/app.rb @@ -29,6 +29,8 @@ before do content_type :json elsif request.path.match /^\/webhooks\// # 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 content_type :html, 'charset' => 'utf-8' redirect '/' if request.post? && !csrf_safe? diff --git a/app/api.rb b/app/api.rb index 5a58902f..02352ad9 100644 --- a/app/api.rb +++ b/app/api.rb @@ -138,6 +138,7 @@ end def require_api_credentials if !request.env['HTTP_AUTHORIZATION'].nil? 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 api_error_invalid_auth end diff --git a/app/settings.rb b/app/settings.rb index ee32e0dc..a89ef315 100644 --- a/app/settings.rb +++ b/app/settings.rb @@ -280,9 +280,15 @@ end post '/settings/change_email' do 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 flash[:error] = 'You are already using this email address for this account.' - redirect '/settings#email' + redirect redirect_url end parent_site.email = params[:email] @@ -292,12 +298,17 @@ post '/settings/change_email' do if parent_site.valid? parent_site.save_changes send_confirmation_email - flash[:success] = 'Successfully changed email. We have sent a confirmation email, please use it to confirm your email address.' - redirect '/settings#email' + if !parent_site.supporter? + session[:fromsettings] = true + redirect "/site/#{parent_site.email}/confirm_email" + else + flash[:success] = 'Email address changed.' + redirect '/settings#email' + end end flash[:error] = parent_site.errors.first.last.first - redirect '/settings#email' + redirect redirect_url end post '/settings/change_email_notification' do diff --git a/app/site.rb b/app/site.rb index eceaffe5..8249504c 100644 --- a/app/site.rb +++ b/app/site.rb @@ -172,8 +172,23 @@ post '/site/create_directory' do end 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]] - 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.save_changes @@ -183,6 +198,47 @@ get '/site/:username/confirm_email/:token' do 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| site = Site[username: username] diff --git a/app_helpers.rb b/app_helpers.rb index 42368c01..85ddba38 100644 --- a/app_helpers.rb +++ b/app_helpers.rb @@ -72,12 +72,19 @@ def encoding_fix(file) end 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({ from: 'web@neocities.org', reply_to: 'contact@neocities.org', to: site.email, 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 @@ -116,3 +123,7 @@ end def dont_browser_cache @dont_browser_cache = true 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 diff --git a/models/site.rb b/models/site.rb index e7703535..b0838f24 100644 --- a/models/site.rb +++ b/models/site.rb @@ -121,6 +121,8 @@ class Site < Sequel::Model maximum_site_files: 2000 ) + EMAIL_VALIDATION_CUTOFF_DATE = Time.now - 1 + def self.newsletter_sites Site.select(:email). exclude(email: 'nil').exclude(is_banned: true). @@ -160,6 +162,8 @@ class Site < Sequel::Model EMAIL_BLAST_MAXIMUM_PER_DAY = 1000 end + MAXIMUM_EMAIL_CONFIRMATIONS = 20 + many_to_many :tags one_to_many :profile_comments diff --git a/public/fonts/dlfonts.sh b/public/fonts/dlfonts.sh old mode 100755 new mode 100644 diff --git a/public/fonts/ocra-webfont.eot b/public/fonts/ocra-webfont.eot old mode 100755 new mode 100644 diff --git a/public/fonts/ocra-webfont.svg b/public/fonts/ocra-webfont.svg old mode 100755 new mode 100644 diff --git a/public/fonts/ocra-webfont.ttf b/public/fonts/ocra-webfont.ttf old mode 100755 new mode 100644 diff --git a/public/fonts/ocra-webfont.woff b/public/fonts/ocra-webfont.woff old mode 100755 new mode 100644 diff --git a/tests/acceptance/settings/account_tests.rb b/tests/acceptance/settings/account_tests.rb index 90a05483..087c29fa 100644 --- a/tests/acceptance/settings/account_tests.rb +++ b/tests/acceptance/settings/account_tests.rb @@ -16,7 +16,14 @@ describe 'site/settings' do @new_email = "#{SecureRandom.uuid.gsub('-', '')}@example.com" fill_in 'email', with: @new_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.email.must_equal @new_email EmailWorker.jobs.length.must_equal 1 diff --git a/tests/acceptance/settings/site_tests.rb b/tests/acceptance/settings/site_tests.rb index 045149ce..ad797303 100644 --- a/tests/acceptance/settings/site_tests.rb +++ b/tests/acceptance/settings/site_tests.rb @@ -345,13 +345,11 @@ describe 'delete' do owned_site = Fabricate :site, parent_site_id: @site.id visit "/settings/#{owned_site.username}#delete" fill_in 'confirm_username', with: owned_site.username - fill_in 'deleted_reason', with: 'got bored with it' click_button 'Delete Site' @site.reload owned_site.reload owned_site.is_deleted.must_equal true - owned_site.deleted_reason.must_equal 'got bored with it' @site.is_deleted.must_equal false page.current_path.must_equal "/settings" diff --git a/tests/acceptance/signup_tests.rb b/tests/acceptance/signup_tests.rb index 08cb5176..69027736 100644 --- a/tests/acceptance/signup_tests.rb +++ b/tests/acceptance/signup_tests.rb @@ -54,6 +54,12 @@ describe 'signup' do click_signup_button 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' File.exist?(index_file_path).must_equal true diff --git a/tests/fabricators/site_fabricator.rb b/tests/fabricators/site_fabricator.rb index 9a16c9a9..9d3dd726 100644 --- a/tests/fabricators/site_fabricator.rb +++ b/tests/fabricators/site_fabricator.rb @@ -1,5 +1,6 @@ Fabricator(:site) do - username { SecureRandom.hex } - password { 'abcde' } - email { SecureRandom.uuid.gsub('-', '')+'@example.com' } -end \ No newline at end of file + username { SecureRandom.hex } + password { 'abcde' } + email { SecureRandom.uuid.gsub('-', '')+'@example.com' } + email_confirmed { true } +end diff --git a/views/_header_links.erb b/views/_header_links.erb index ec317af4..7a1ce4a3 100644 --- a/views/_header_links.erb +++ b/views/_header_links.erb @@ -15,5 +15,13 @@ Learn
  • - Support Us -
  • \ No newline at end of file + + <% if signed_in? %> + <% unless current_site.supporter? %> + Upgrade to Supporter + <% end %> + <% else %> + Support Us + <% end %> + + diff --git a/views/_team.erb b/views/_team.erb index dcfdb96f..24ecc18e 100644 --- a/views/_team.erb +++ b/views/_team.erb @@ -3,31 +3,24 @@

    The Neocities Team

    -
    + -

    Follow us on Twitter or Facebook

    -
    \ No newline at end of file + diff --git a/views/site/confirm_email.erb b/views/site/confirm_email.erb new file mode 100644 index 00000000..2a2ab660 --- /dev/null +++ b/views/site/confirm_email.erb @@ -0,0 +1,51 @@ +
    +

    Check your Email

    +
    +

    + <% if !@fromsettings %> + You're almost ready!
    + <% end %> + + We sent an email to <%= current_site.email %> to make sure it's correct.
    Please check your email, enter the confirmation code here, and you're all set. +

    + +
    +
    + + <% if flash[:success] %> +
    + <%== flash[:success] %> +
    + <% end %> + + <% if flash[:error] %> +
    + <%== flash[:error] %> +
    + <% end %> + +
    + <%== csrf_token_input_html %> +
    + + +
    + +
    + +

    Wrong email?

    +

    If you entered the wrong email address by mistake:

    + +
    + <%== csrf_token_input_html %> + +
    + +
    + +
    + +
    +
    + +
    diff --git a/views/templates/email_confirm.erb b/views/templates/email/confirm.erb similarity index 55% rename from views/templates/email_confirm.erb rename to views/templates/email/confirm.erb index fcd5a30f..b83b0be2 100644 --- a/views/templates/email_confirm.erb +++ b/views/templates/email/confirm.erb @@ -2,11 +2,13 @@ Hello <%= site.username %>, 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 %> Thank you! -- The Neocities Team \ No newline at end of file +- The Neocities Team