Fix link verification for remote accounts (#8868)

pull/8879/merge
Eugen Rochko 7 years ago committed by GitHub
parent 49b182cd51
commit 7fe137d2f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -312,8 +312,8 @@ class Account < ApplicationRecord
def initialize(account, attributes) def initialize(account, attributes)
@account = account @account = account
@attributes = attributes @attributes = attributes
@name = attributes['name'].strip[0, 255] @name = attributes['name'].strip[0, string_limit]
@value = attributes['value'].strip[0, 255] @value = attributes['value'].strip[0, string_limit]
@verified_at = attributes['verified_at']&.to_datetime @verified_at = attributes['verified_at']&.to_datetime
@errors = {} @errors = {}
end end
@ -322,8 +322,18 @@ class Account < ApplicationRecord
verified_at.present? verified_at.present?
end end
def value_for_verification
@value_for_verification ||= begin
if account.local?
value
else
ActionController::Base.helpers.strip_tags(value)
end
end
end
def verifiable? def verifiable?
value.present? && value.start_with?('http://', 'https://') value_for_verification.present? && value_for_verification.start_with?('http://', 'https://')
end end
def mark_verified! def mark_verified!
@ -334,6 +344,16 @@ class Account < ApplicationRecord
def to_h def to_h
{ name: @name, value: @value, verified_at: @verified_at } { name: @name, value: @value, verified_at: @verified_at }
end end
private
def string_limit
if account.local?
255
else
2047
end
end
end end
class << self class << self

@ -11,11 +11,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
has_many :emojis, serializer: REST::CustomEmojiSerializer has_many :emojis, serializer: REST::CustomEmojiSerializer
class FieldSerializer < ActiveModel::Serializer class FieldSerializer < ActiveModel::Serializer
attributes :name, :value attributes :name, :value, :verified_at
attribute :verified_at, if: :verifiable?
delegate :verifiable?, to: :object
def value def value
Formatter.instance.format_field(object.account, object.value) Formatter.instance.format_field(object.account, object.value)

@ -3,7 +3,7 @@
class VerifyLinkService < BaseService class VerifyLinkService < BaseService
def call(field) def call(field)
@link_back = ActivityPub::TagManager.instance.url_for(field.account) @link_back = ActivityPub::TagManager.instance.url_for(field.account)
@url = field.value @url = field.value_for_verification
perform_request! perform_request!

@ -3,80 +3,107 @@ require 'rails_helper'
RSpec.describe VerifyLinkService, type: :service do RSpec.describe VerifyLinkService, type: :service do
subject { described_class.new } subject { described_class.new }
let(:account) { Fabricate(:account, username: 'alice') } context 'given a local account' do
let(:field) { Account::Field.new(account, 'name' => 'Website', 'value' => 'http://example.com') } let(:account) { Fabricate(:account, username: 'alice') }
let(:field) { Account::Field.new(account, 'name' => 'Website', 'value' => 'http://example.com') }
before do before do
stub_request(:head, 'https://redirect.me/abc').to_return(status: 301, headers: { 'Location' => ActivityPub::TagManager.instance.url_for(account) }) stub_request(:head, 'https://redirect.me/abc').to_return(status: 301, headers: { 'Location' => ActivityPub::TagManager.instance.url_for(account) })
stub_request(:get, 'http://example.com').to_return(status: 200, body: html) stub_request(:get, 'http://example.com').to_return(status: 200, body: html)
subject.call(field) subject.call(field)
end
context 'when a link contains an <a> back' do
let(:html) do
<<-HTML
<!doctype html>
<body>
<a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="me">Follow me on Mastodon</a>
</body>
HTML
end end
it 'marks the field as verified' do context 'when a link contains an <a> back' do
expect(field.verified?).to be true let(:html) do
<<-HTML
<!doctype html>
<body>
<a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="me">Follow me on Mastodon</a>
</body>
HTML
end
it 'marks the field as verified' do
expect(field.verified?).to be true
end
end end
end
context 'when a link contains an <a rel="noopener"> back' do context 'when a link contains an <a rel="noopener"> back' do
let(:html) do let(:html) do
<<-HTML <<-HTML
<!doctype html> <!doctype html>
<body> <body>
<a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="noopener me" target="_blank">Follow me on Mastodon</a> <a href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="noopener me" target="_blank">Follow me on Mastodon</a>
</body> </body>
HTML HTML
end
it 'marks the field as verified' do
expect(field.verified?).to be true
end
end end
it 'marks the field as verified' do context 'when a link contains a <link> back' do
expect(field.verified?).to be true let(:html) do
<<-HTML
<!doctype html>
<head>
<link type="text/html" href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="me" />
</head>
HTML
end
it 'marks the field as verified' do
expect(field.verified?).to be true
end
end end
end
context 'when a link contains a <link> back' do context 'when a link goes through a redirect back' do
let(:html) do let(:html) do
<<-HTML <<-HTML
<!doctype html> <!doctype html>
<head> <head>
<link type="text/html" href="#{ActivityPub::TagManager.instance.url_for(account)}" rel="me" /> <link type="text/html" href="https://redirect.me/abc" rel="me" />
</head> </head>
HTML HTML
end
it 'marks the field as verified' do
expect(field.verified?).to be true
end
end end
it 'marks the field as verified' do context 'when a link does not contain a link back' do
expect(field.verified?).to be true let(:html) { '' }
it 'marks the field as verified' do
expect(field.verified?).to be false
end
end end
end end
context 'when a link goes through a redirect back' do context 'given a remote account' do
let(:html) do let(:account) { Fabricate(:account, username: 'alice', domain: 'example.com', url: 'https://profile.example.com/alice') }
<<-HTML let(:field) { Account::Field.new(account, 'name' => 'Website', 'value' => '<a href="http://example.com" rel="me"><span class="invisible">http://</span><span class="">example.com</span><span class="invisible"></span></a>') }
<!doctype html>
<head>
<link type="text/html" href="https://redirect.me/abc" rel="me" />
</head>
HTML
end
it 'marks the field as verified' do before do
expect(field.verified?).to be true stub_request(:get, 'http://example.com').to_return(status: 200, body: html)
subject.call(field)
end end
end
context 'when a link does not contain a link back' do context 'when a link contains an <a> back' do
let(:html) { '' } let(:html) do
<<-HTML
<!doctype html>
<body>
<a href="https://profile.example.com/alice" rel="me">Follow me on Mastodon</a>
</body>
HTML
end
it 'marks the field as verified' do it 'marks the field as verified' do
expect(field.verified?).to be false expect(field.verified?).to be true
end
end end
end end
end end

Loading…
Cancel
Save