Files
jcoffey-dev 319ed76dbd
Crowdin / Upload translations / upload-translations (push) Skipped
Historical data migration test / test (14-alpine) (push) Canceled after 0s
Historical data migration test / test (15-alpine) (push) Canceled after 0s
Historical data migration test / test (16-alpine) (push) Canceled after 0s
Historical data migration test / test (17-alpine) (push) Canceled after 0s
Bundler Audit / security (push) Canceled after 0s
Haml Linting / lint (push) Canceled after 0s
JavaScript Linting / lint (push) Canceled after 0s
Ruby Linting / lint (push) Canceled after 0s
JavaScript Testing / test (push) Canceled after 0s
Ruby Testing / build (production) (push) Canceled after 0s
Ruby Testing / test (.ruby-version) (push) Canceled after 0s
Ruby Testing / test (3.3) (push) Canceled after 0s
Ruby Testing / test (3.4) (push) Canceled after 0s
Ruby Testing / End to End testing (.ruby-version) (push) Canceled after 0s
Ruby Testing / End to End testing (3.3) (push) Canceled after 0s
Ruby Testing / End to End testing (3.4) (push) Canceled after 0s
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.29) (push) Canceled after 0s
Check i18n / check-i18n (push) Canceled after 0s
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (javascript) (push) Canceled after 0s
CodeQL / Analyze (ruby) (push) Canceled after 0s
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Canceled after 0s
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.29) (push) Canceled after 0s
Ruby Testing / Elastic Search integration testing (3.4, docker.elastic.co/elasticsearch/elasticsearch:7.17.29) (push) Canceled after 0s
Check formatting / lint (push) Canceled after 0s
CSS Linting / lint (push) Canceled after 0s
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.19.2) (push) Canceled after 0s
Chromatic / Check for relevant changes (push) Canceled after 0s
Chromatic / Run Chromatic (push) Canceled after 0s
Import Mastodon v4.7.3
Snapshot of upstream tag v4.7.3 (commit 8ff11c2bb7b9f0714e947b10fa3629c6542c7121) from
https://github.com/mastodon/mastodon, unmodified.
2026-10-05 22:03:13 -07:00

95 lines
2.4 KiB
Ruby

# frozen_string_literal: true
class Account::Field < ActiveModelSerializers::Model
MAX_CHARACTERS_LOCAL = 255
MAX_CHARACTERS_COMPAT = 2_047
ACCEPTED_SCHEMES = %w(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 ||= if account.local?
value
else
extract_url_from_html
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 &&
(parsed_url.path.empty? || parsed_url.path == parsed_url.normalized_path)
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
begin
doc = Nokogiri::HTML5.fragment(value)
rescue ArgumentError
# This can happen if one of the Nokogumbo limits is encountered
# Unfortunately, it does not use a more precise error class
# nor allows more graceful handling
return
end
return if doc.nil?
return if doc.children.size != 1
element = doc.children.first
return if element.name != 'a' || element['href'] != element.text
element['href']
end
end