about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2022-11-10 06:27:45 +0100
committerGitHub <noreply@github.com>2022-11-10 06:27:45 +0100
commit9965a23b043b0ab511e083c44acda891ea441859 (patch)
treec1281562aca885ca3cea65e5722d0d7a13e85ec5
parent78a6b871fe3dae308380ea88132ddadc86a1431e (diff)
Change link verification to ignore IDN domains (#20295)
Fix #3833
-rw-r--r--app/models/account/field.rb16
-rw-r--r--spec/models/account/field_spec.rb8
2 files changed, 23 insertions, 1 deletions
diff --git a/app/models/account/field.rb b/app/models/account/field.rb
index 4e0fd9230..d74f90b2b 100644
--- a/app/models/account/field.rb
+++ b/app/models/account/field.rb
@@ -3,6 +3,7 @@
 class Account::Field < ActiveModelSerializers::Model
   MAX_CHARACTERS_LOCAL  = 255
   MAX_CHARACTERS_COMPAT = 2_047
+  ACCEPTED_SCHEMES      = %w(http https).freeze
 
   attributes :name, :value, :verified_at, :account
 
@@ -34,7 +35,20 @@ class Account::Field < ActiveModelSerializers::Model
   end
 
   def verifiable?
-    value_for_verification.present? && /\A#{FetchLinkCardService::URL_PATTERN}\z/.match?(value_for_verification)
+    return false if value_for_verification.blank?
+
+    # This is slower than checking through a regular expression, but we
+    # need to confirm that it's not an IDN domain.
+
+    parsed_url = Addressable::URI.parse(value_for_verification)
+
+    ACCEPTED_SCHEMES.include?(parsed_url.scheme) &&
+      parsed_url.user.nil? &&
+      parsed_url.password.nil? &&
+      parsed_url.host.present? &&
+      parsed_url.normalized_host == parsed_url.host
+  rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError
+    false
   end
 
   def requires_verification?
diff --git a/spec/models/account/field_spec.rb b/spec/models/account/field_spec.rb
index 7d61a2c62..fcb2a884a 100644
--- a/spec/models/account/field_spec.rb
+++ b/spec/models/account/field_spec.rb
@@ -66,6 +66,14 @@ RSpec.describe Account::Field, type: :model do
         end
       end
 
+      context 'for an IDN URL' do
+        let(:value) { 'http://twitter.com∕dougallj∕status∕1590357240443437057.ê.cc/twitter.html' }
+
+        it 'returns false' do
+          expect(subject.verifiable?).to be false
+        end
+      end
+
       context 'for text that is not a URL' do
         let(:value) { 'Hello world' }