diff options
author | Claire <claire.github-309c@sitedethib.com> | 2022-11-10 13:27:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-10 13:27:40 +0100 |
commit | ee7e49d1b1323618e16026bc8db8ab7f9459cc2d (patch) | |
tree | 86d51ac7c13d2b08fae534a44524c2ef8b131315 /app/models/account/field.rb | |
parent | b2a25d446a9f4368ad9d1240b9da30bc33942da5 (diff) | |
parent | c4d2c729245fab1dda31d0de73be9bc03217b06a (diff) |
Merge pull request #1910 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
Diffstat (limited to 'app/models/account/field.rb')
-rw-r--r-- | app/models/account/field.rb | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/app/models/account/field.rb b/app/models/account/field.rb new file mode 100644 index 000000000..d74f90b2b --- /dev/null +++ b/app/models/account/field.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +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 + + def initialize(account, attributes) + # Keeping this as reference allows us to update the field on the account + # from methods in this class, so that changes can be saved. + @original_field = attributes + @account = account + + super( + name: sanitize(attributes['name']), + value: sanitize(attributes['value']), + verified_at: attributes['verified_at']&.to_datetime, + ) + end + + def verified? + verified_at.present? + end + + def value_for_verification + @value_for_verification ||= begin + if account.local? + value + else + extract_url_from_html + end + end + end + + def verifiable? + 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? + !verified? && verifiable? + end + + def mark_verified! + @original_field['verified_at'] = self.verified_at = Time.now.utc + end + + def to_h + { name: name, value: value, verified_at: verified_at } + end + + private + + def sanitize(str) + str.strip[0, character_limit] + end + + def character_limit + account.local? ? MAX_CHARACTERS_LOCAL : MAX_CHARACTERS_COMPAT + end + + def extract_url_from_html + doc = Nokogiri::HTML(value).at_xpath('//body') + + return if doc.children.size > 1 + + element = doc.children.first + + return if element.name != 'a' || element['href'] != element.text + + element['href'] + end +end |