fix: allow verification when page size exceeds 1MB (using HTML5 parser) (#22879)
* fix: allow verification when page size exceeds 1MB Truncates the page after 1MB instead Closes #15316 * switch to HTML5 parser, fix rubocop errors * undo rubocop fixes Co-authored-by: Chris Zubak-Skees <chriszs@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							fd33bcb3b2
						
					
				
				
					commit
					0c689b9d01
				
			@@ -154,9 +154,7 @@ class Request
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  module ClientLimit
 | 
			
		||||
    def body_with_limit(limit = 1.megabyte)
 | 
			
		||||
      raise Mastodon::LengthValidationError if content_length.present? && content_length > limit
 | 
			
		||||
 | 
			
		||||
    def truncated_body(limit = 1.megabyte)
 | 
			
		||||
      if charset.nil?
 | 
			
		||||
        encoding = Encoding::BINARY
 | 
			
		||||
      else
 | 
			
		||||
@@ -173,11 +171,19 @@ class Request
 | 
			
		||||
        contents << chunk
 | 
			
		||||
        chunk.clear
 | 
			
		||||
 | 
			
		||||
        raise Mastodon::LengthValidationError if contents.bytesize > limit
 | 
			
		||||
        break if contents.bytesize > limit
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      contents
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def body_with_limit(limit = 1.megabyte)
 | 
			
		||||
      raise Mastodon::LengthValidationError if content_length.present? && content_length > limit
 | 
			
		||||
 | 
			
		||||
      contents = truncated_body(limit)
 | 
			
		||||
      raise Mastodon::LengthValidationError if contents.bytesize > limit
 | 
			
		||||
      contents
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  if ::HTTP::Response.methods.include?(:body_with_limit) && !Rails.env.production?
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ class VerifyLinkService < BaseService
 | 
			
		||||
  def link_back_present?
 | 
			
		||||
    return false if @body.blank?
 | 
			
		||||
 | 
			
		||||
    links = Nokogiri::HTML(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]')
 | 
			
		||||
    links = Nokogiri::HTML5(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]')
 | 
			
		||||
 | 
			
		||||
    if links.any? { |link| link['href']&.downcase == @link_back.downcase }
 | 
			
		||||
      true
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,11 @@ describe Request do
 | 
			
		||||
      expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'truncates large monolithic body' do
 | 
			
		||||
      stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes })
 | 
			
		||||
      expect(subject.perform { |response| response.truncated_body.bytesize }).to be < 2.megabytes
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'uses binary encoding if Content-Type does not tell encoding' do
 | 
			
		||||
      stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html' })
 | 
			
		||||
      expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,33 @@ RSpec.describe VerifyLinkService, type: :service do
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when a document is truncated but the link back is valid' do
 | 
			
		||||
      let(:html) do
 | 
			
		||||
        "
 | 
			
		||||
          <!doctype html>
 | 
			
		||||
          <body>
 | 
			
		||||
            <a rel=\"me\" href=\"#{ActivityPub::TagManager.instance.url_for(account)}\"
 | 
			
		||||
        "
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'marks the field as not verified' do
 | 
			
		||||
        expect(field.verified?).to be false
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when a link back might be truncated' do
 | 
			
		||||
      let(:html) do
 | 
			
		||||
        "
 | 
			
		||||
          <!doctype html>
 | 
			
		||||
          <body>
 | 
			
		||||
            <a rel=\"me\" href=\"#{ActivityPub::TagManager.instance.url_for(account)}"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'does not mark the field as verified' do
 | 
			
		||||
        expect(field.verified?).to be false
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when a link does not contain a link back' do
 | 
			
		||||
      let(:html) { '' }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user