From 143704215faceb2e9b27abf9f15d4f4393716469 Mon Sep 17 00:00:00 2001 From: Kyle Drake Date: Thu, 9 Nov 2023 14:55:48 -0600 Subject: [PATCH] first pass at phone validation --- Gemfile | 2 + Gemfile.lock | 8 ++++ app.rb | 2 + app/create.rb | 1 + app/site.rb | 58 +++++++++++++++++++++++++++ environment.rb | 2 + migrations/119_verify_phone.rb | 15 +++++++ models/site.rb | 5 +++ views/site/confirm_email.erb | 2 +- views/site/confirm_phone.erb | 73 ++++++++++++++++++++++++++++++++++ 10 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 migrations/119_verify_phone.rb create mode 100644 views/site/confirm_phone.erb diff --git a/Gemfile b/Gemfile index 8c43be89..c426ed08 100644 --- a/Gemfile +++ b/Gemfile @@ -58,6 +58,8 @@ gem 'rss' gem 'webp-ffi' gem 'rszr' gem 'zip_tricks' +gem 'twilio-ruby' +gem 'phonelib' group :development, :test do gem 'pry' diff --git a/Gemfile.lock b/Gemfile.lock index a23517f0..3f0a6e1c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -142,6 +142,7 @@ GEM io-extra (1.4.0) ipaddress (0.8.3) json (2.6.2) + jwt (2.7.1) llhttp-ffi (0.4.0) ffi-compiler (~> 1.0) rake (~> 13.0) @@ -192,6 +193,7 @@ GEM ox (2.14.11) paypal-recurring (1.1.0) pg (1.5.3) + phonelib (0.8.3) progress (3.6.0) pry (0.14.1) coderay (~> 1.1) @@ -286,6 +288,10 @@ GEM timeout (0.3.0) tins (1.31.1) sync + twilio-ruby (6.3.1) + faraday (>= 0.9, < 3.0) + jwt (>= 1.5, < 3.0) + nokogiri (>= 1.6, < 2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unf (0.1.4) @@ -356,6 +362,7 @@ DEPENDENCIES nokogiri paypal-recurring pg + phonelib pry puma (< 7) rack-cache @@ -385,6 +392,7 @@ DEPENDENCIES thread tilt timecop + twilio-ruby webmock webp-ffi will_paginate diff --git a/app.rb b/app.rb index f5a9d9b1..82d621f3 100644 --- a/app.rb +++ b/app.rb @@ -77,6 +77,8 @@ before do # Skips the CSRF/validation check for stripe web hooks elsif email_not_validated? && !(request.path =~ /^\/site\/.+\/confirm_email|^\/settings\/change_email|^\/signout|^\/welcome|^\/supporter/) redirect "/site/#{current_site.username}/confirm_email" + elsif current_site && current_site.phone_verification_needed? && !(request.path =~ /^\/site\/.+\/confirm_phone/) + redirect "/site/#{current_site.username}/confirm_phone" else content_type :html, 'charset' => 'utf-8' redirect '/' if request.post? && !csrf_safe? diff --git a/app/create.rb b/app/create.rb index 80c38269..5dfbb3de 100644 --- a/app/create.rb +++ b/app/create.rb @@ -98,6 +98,7 @@ post '/create' do end @site.email_confirmed = true if self.class.development? + #@site.phone_confirmed = true if self.class.development? @site.save unless education_whitelisted? diff --git a/app/site.rb b/app/site.rb index 18e2ce89..546dfd0e 100644 --- a/app/site.rb +++ b/app/site.rb @@ -295,4 +295,62 @@ get '/site/:username/unblock' do |username| current_site.unblock! site redirect request.referer +end + +get '/site/:username/confirm_phone' do + require_login + redirect '/' unless current_site.phone_verification_needed? + @title = 'Verify your Phone Number' + erb :'site/confirm_phone' +end + +post '/site/:username/confirm_phone' do + require_login + redirect '/' unless current_site.phone_verification_needed? + + if params[:phone_intl] + phone = Phonelib.parse params[:phone_intl] + + if !phone.valid? + flash[:error] = "Invalid phone number, please try again." + redirect "/site/#{current_site.username}/confirm_phone" + end + + if phone.types.include?(:premium_rate) || phone.types.include?(:shared_cost) + flash[:error] = 'Neocities does not support this type of number, please use another number.' + redirect "/site/#{current_site.username}/confirm_phone" + end + + current_site.phone_verification_sent_at = Time.now + current_site.save_changes validate: false + + verification = $twilio.verify + .v2 + .services($config['twilio_service_sid']) + .verifications + .create(to: phone.e164, channel: 'sms') + + current_site.phone_verification_sid = verification.sid + current_site.save_changes validate: false + + flash[:success] = 'Validation message sent! Check your phone and enter the code below.' + else + # Check code + vc = $twilio.verify + .v2 + .services($config['twilio_service_sid']) + .verification_checks + .create(verification_sid: current_site.phone_verification_sid, code: params[:code]) + + # puts vc.status (pending if failed, approved if it passed) + if vc.status == 'approved' + current_site.phone_verified = true + current_site.save_changes validate: false + else + flash[:error] = 'Code was not correct, please re-enter.' + end + end + + # Will redirect to / automagically if phone was verified + redirect "/site/#{current_site.username}/confirm_phone" end \ No newline at end of file diff --git a/environment.rb b/environment.rb index de6d5231..cbcba539 100644 --- a/environment.rb +++ b/environment.rb @@ -177,3 +177,5 @@ $image_optim = ImageOptim.new pngout: false, svgo: false Money.locale_backend = nil Money.default_currency = Money::Currency.new("USD") Money.rounding_mode = BigDecimal::ROUND_HALF_UP + +$twilio = Twilio::REST::Client.new $config['twilio_account_sid'], $config['twilio_auth_token'] diff --git a/migrations/119_verify_phone.rb b/migrations/119_verify_phone.rb new file mode 100644 index 00000000..206e1cae --- /dev/null +++ b/migrations/119_verify_phone.rb @@ -0,0 +1,15 @@ +Sequel.migration do + up { + DB.add_column :sites, :phone_verification_required, :boolean, default: false + DB.add_column :sites, :phone_verified, :boolean, default: false + DB.add_column :sites, :phone_verification_sid, :text + DB.add_column :sites, :phone_verification_sent_at, :time + } + + down { + DB.drop_column :sites, :phone_verification_required + DB.drop_column :sites, :phone_verified + DB.drop_column :sites, :phone_verification_sid + DB.drop_column :sites, :phone_verification_sent_at + } +end \ No newline at end of file diff --git a/models/site.rb b/models/site.rb index a0cc7290..30864524 100644 --- a/models/site.rb +++ b/models/site.rb @@ -1789,6 +1789,11 @@ class Site < Sequel::Model end end + def phone_verification_needed? + return true if phone_verification_required && !phone_verified + false + end + private def store_file(path, uploaded, opts={}) diff --git a/views/site/confirm_email.erb b/views/site/confirm_email.erb index 2a2ab660..553b928d 100644 --- a/views/site/confirm_email.erb +++ b/views/site/confirm_email.erb @@ -6,7 +6,7 @@ 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. + We sent an email to <%= current_site.email %> to make sure it's correct.
Please check your email, and enter the confirmation code here.
diff --git a/views/site/confirm_phone.erb b/views/site/confirm_phone.erb new file mode 100644 index 00000000..ba0287c0 --- /dev/null +++ b/views/site/confirm_phone.erb @@ -0,0 +1,73 @@ +
+

Verify your phone number

+
+

+ You're almost ready!
+ To prevent spam and keep the searchability of your site high, we have one last step: +
please verify your mobile phone number. +

+ +
+
+ <% if flash[:success] %> +
+ <%== flash[:success] %> +
+ <% end %> + + <% if flash[:error] %> +
+ <%== flash[:error] %> +
+ <% end %> + +
+ <%== csrf_token_input_html %> + + <% if current_site.phone_verification_sid %> +
+ + +
+ + <% else %> + +
+ + + +
+ + + + + + + + <% end %> + +
+
+
+ +