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' }