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.