create entity fetcher for public entities

This commit is contained in:
Benjamin Neff 2016-03-13 02:31:20 +01:00
parent 4a7fd52844
commit d83b6f14f5
5 changed files with 108 additions and 4 deletions

View file

@ -4,5 +4,6 @@ module DiasporaFederation
end
end
require "diaspora_federation/federation/fetcher"
require "diaspora_federation/federation/receiver"
require "diaspora_federation/federation/sender"

View file

@ -0,0 +1,26 @@
module DiasporaFederation
module Federation
# this module is for fetching entities from other pods
module Fetcher
# fetches a public entity from a remote pod
# @param [String] author the diaspora ID of the author of the entity
# @param [Symbol, String] entity_type snake_case version of the entity class
# @param [String] guid guid of the entity to fetch
def self.fetch_public(author, entity_type, guid)
url = DiasporaFederation.callbacks.trigger(:fetch_person_url_to, author, "/fetch/#{entity_type}/#{guid}")
response = DiasporaFederation::Fetcher.get(url)
raise "Failed to fetch #{url}: #{response.status}" unless response.success?
magic_env = Nokogiri::XML::Document.parse(response.body).root
entity = Salmon::MagicEnvelope.unenvelop(magic_env)
DiasporaFederation.callbacks.trigger(:save_entity_after_receive, entity)
rescue => e
raise NotFetchable, "Failed to fetch #{entity_type}:#{guid} from #{author}: #{e.class}: #{e.message}"
end
# Raised, if the entity is not fetchable
class NotFetchable < RuntimeError
end
end
end
end

View file

@ -0,0 +1,76 @@
module DiasporaFederation
describe Federation::Fetcher do
let(:post) { FactoryGirl.build(:status_message_entity, public: true) }
let(:post_magic_env) { Salmon::MagicEnvelope.new(post).envelop(alice.private_key, post.author).to_xml }
describe ".fetch_public" do
it "fetches a public post" do
stub_request(:get, "https://example.org/fetch/post/#{post.guid}")
.to_return(status: 200, body: post_magic_env)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_person_url_to, post.author, "/fetch/post/#{post.guid}"
).and_return("https://example.org/fetch/post/#{post.guid}")
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_public_key_by_diaspora_id, post.author
).and_return(alice.public_key)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:save_entity_after_receive, kind_of(Entities::StatusMessage)
) do |_, entity|
expect(entity.guid).to eq(post.guid)
expect(entity.author).to eq(post.author)
expect(entity.raw_message).to eq(post.raw_message)
expect(entity.public).to eq("true")
end
Federation::Fetcher.fetch_public(post.author, :post, post.guid)
end
it "follows redirects" do
stub_request(:get, "https://example.org/fetch/post/#{post.guid}")
.to_return(status: 302, headers: {"Location" => "https://example.com/fetch/post/#{post.guid}"})
stub_request(:get, "https://example.com/fetch/post/#{post.guid}")
.to_return(status: 200, body: post_magic_env)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_person_url_to, post.author, "/fetch/post/#{post.guid}"
).and_return("https://example.org/fetch/post/#{post.guid}")
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_public_key_by_diaspora_id, post.author
).and_return(alice.public_key)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:save_entity_after_receive, kind_of(Entities::StatusMessage)
)
Federation::Fetcher.fetch_public(post.author, :post, post.guid)
end
it "raises NotFetchable if post not found (private)" do
stub_request(:get, "https://example.org/fetch/post/#{post.guid}")
.to_return(status: 404)
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_person_url_to, post.author, "/fetch/post/#{post.guid}"
).and_return("https://example.org/fetch/post/#{post.guid}")
expect {
Federation::Fetcher.fetch_public(post.author, :post, post.guid)
}.to raise_error Federation::Fetcher::NotFetchable
end
it "raises NotFetchable if connection refused" do
expect(DiasporaFederation::Fetcher).to receive(:get).with(
"https://example.org/fetch/post/#{post.guid}"
).and_raise(Faraday::ConnectionFailed, "Couldn't connect to server")
expect(DiasporaFederation.callbacks).to receive(:trigger).with(
:fetch_person_url_to, post.author, "/fetch/post/#{post.guid}"
).and_return("https://example.org/fetch/post/#{post.guid}")
expect {
Federation::Fetcher.fetch_public(post.author, :post, post.guid)
}.to raise_error Federation::Fetcher::NotFetchable
end
end
end
end

View file

@ -85,10 +85,8 @@ shared_examples "a relayable Entity" do
author_signature = xml.at_xpath("post/*[1]/author_signature").text
parent_author_signature = xml.at_xpath("post/*[1]/parent_author_signature").text
alice_public_key = OpenSSL::PKey::RSA.new(alice.serialized_public_key)
bob_public_key = OpenSSL::PKey::RSA.new(bob.serialized_public_key)
expect(verify_signature(alice_public_key, author_signature, signed_string)).to be_truthy
expect(verify_signature(bob_public_key, parent_author_signature, signed_string)).to be_truthy
expect(verify_signature(alice.public_key, author_signature, signed_string)).to be_truthy
expect(verify_signature(bob.public_key, parent_author_signature, signed_string)).to be_truthy
end
end
end

View file

@ -1,6 +1,9 @@
class Person < ActiveRecord::Base
include ::Diaspora::Guid
def private_key; OpenSSL::PKey::RSA.new(serialized_private_key) end
def public_key; OpenSSL::PKey::RSA.new(serialized_public_key) end
def alias_url; "#{url}people/#{guid}" end
def hcard_url; "#{url}hcard/users/#{guid}" end
def profile_url; "#{url}u/#{nickname}" end