Fetch RFC 7033 WebFinger with fallback to legacy WebFinger
This commit is contained in:
parent
6852f9ca36
commit
3e7e649025
2 changed files with 137 additions and 40 deletions
|
|
@ -58,23 +58,33 @@ module DiasporaFederation
|
||||||
retry
|
retry
|
||||||
end
|
end
|
||||||
|
|
||||||
def host_meta_url
|
def domain
|
||||||
domain = diaspora_id.split("@")[1]
|
@domain ||= diaspora_id.split("@")[1]
|
||||||
"https://#{domain}/.well-known/host-meta"
|
end
|
||||||
|
|
||||||
|
def acct_parameter
|
||||||
|
"acct:#{diaspora_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def legacy_webfinger_url_from_host_meta
|
def legacy_webfinger_url_from_host_meta
|
||||||
# This tries the xrd url with https first, then falls back to http.
|
# This tries the xrd url with https first, then falls back to http.
|
||||||
host_meta = HostMeta.from_xml get(host_meta_url, true)
|
host_meta = HostMeta.from_xml(get("https://#{domain}/.well-known/host-meta", true))
|
||||||
host_meta.webfinger_template_url.gsub("{uri}", "acct:#{diaspora_id}")
|
host_meta.webfinger_template_url.gsub("{uri}", acct_parameter)
|
||||||
end
|
end
|
||||||
|
|
||||||
def webfinger
|
def webfinger
|
||||||
@webfinger ||= WebFinger.from_xml get(legacy_webfinger_url_from_host_meta)
|
return @webfinger if @webfinger
|
||||||
|
webfinger_url = "https://#{domain}/.well-known/webfinger?resource=#{acct_parameter}"
|
||||||
|
|
||||||
|
# This tries the WebFinger URL with https first, then falls back to http.
|
||||||
|
@webfinger = WebFinger.from_json(get(webfinger_url, true))
|
||||||
|
rescue => e
|
||||||
|
logger.warn "WebFinger failed, retrying with legacy WebFinger for #{diaspora_id}: #{e.class}: #{e.message}"
|
||||||
|
@webfinger = WebFinger.from_xml(get(legacy_webfinger_url_from_host_meta))
|
||||||
end
|
end
|
||||||
|
|
||||||
def hcard
|
def hcard
|
||||||
@hcard ||= HCard.from_html get(webfinger.hcard_url)
|
@hcard ||= HCard.from_html(get(webfinger.hcard_url))
|
||||||
end
|
end
|
||||||
|
|
||||||
def person
|
def person
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
module DiasporaFederation
|
module DiasporaFederation
|
||||||
describe Discovery::Discovery do
|
describe Discovery::Discovery do
|
||||||
let(:host_meta_xrd) { Discovery::HostMeta.from_base_url("http://localhost:3000/").to_xml }
|
let(:host_meta_xrd) { Discovery::HostMeta.from_base_url("http://localhost:3000/").to_xml }
|
||||||
let(:webfinger_xrd) {
|
let(:webfinger_data) {
|
||||||
DiasporaFederation::Discovery::WebFinger.new(
|
{
|
||||||
acct_uri: "acct:#{alice.diaspora_id}",
|
acct_uri: "acct:#{alice.diaspora_id}",
|
||||||
alias_url: alice.alias_url,
|
alias_url: alice.alias_url,
|
||||||
hcard_url: alice.hcard_url,
|
hcard_url: alice.hcard_url,
|
||||||
|
|
@ -13,7 +13,13 @@ module DiasporaFederation
|
||||||
subscribe_url: alice.subscribe_url,
|
subscribe_url: alice.subscribe_url,
|
||||||
guid: alice.guid,
|
guid: alice.guid,
|
||||||
public_key: alice.serialized_public_key
|
public_key: alice.serialized_public_key
|
||||||
).to_xml
|
}
|
||||||
|
}
|
||||||
|
let(:webfinger_xrd) {
|
||||||
|
DiasporaFederation::Discovery::WebFinger.new(webfinger_data).to_xml
|
||||||
|
}
|
||||||
|
let(:webfinger_jrd) {
|
||||||
|
JSON.pretty_generate(DiasporaFederation::Discovery::WebFinger.new(webfinger_data).to_json)
|
||||||
}
|
}
|
||||||
let(:hcard_html) {
|
let(:hcard_html) {
|
||||||
DiasporaFederation::Discovery::HCard.new(
|
DiasporaFederation::Discovery::HCard.new(
|
||||||
|
|
@ -32,6 +38,7 @@ module DiasporaFederation
|
||||||
}
|
}
|
||||||
let(:account) { alice.diaspora_id }
|
let(:account) { alice.diaspora_id }
|
||||||
let(:default_image) { "http://localhost:3000/assets/user/default.png" }
|
let(:default_image) { "http://localhost:3000/assets/user/default.png" }
|
||||||
|
subject { Discovery::Discovery.new(account) }
|
||||||
|
|
||||||
describe "#intialize" do
|
describe "#intialize" do
|
||||||
it "sets diaspora* ID" do
|
it "sets diaspora* ID" do
|
||||||
|
|
@ -47,15 +54,13 @@ module DiasporaFederation
|
||||||
|
|
||||||
describe ".fetch_and_save" do
|
describe ".fetch_and_save" do
|
||||||
it "fetches the userdata and returns a person object" do
|
it "fetches the userdata and returns a person object" do
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
.to_return(status: 200, body: webfinger_jrd)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
|
||||||
.to_return(status: 200, body: webfinger_xrd)
|
|
||||||
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
.to_return(status: 200, body: hcard_html)
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
person = Discovery::Discovery.new(account).fetch_and_save
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
expect(person.guid).to eq(alice.guid)
|
expect(person.guid).to eq(alice.guid)
|
||||||
expect(person.diaspora_id).to eq(account)
|
expect(person.diaspora_id).to eq(account)
|
||||||
|
|
@ -74,10 +79,8 @@ module DiasporaFederation
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fetches the userdata and saves the person object via callback" do
|
it "fetches the userdata and saves the person object via callback" do
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
.to_return(status: 200, body: webfinger_jrd)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
|
||||||
.to_return(status: 200, body: webfinger_xrd)
|
|
||||||
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
.to_return(status: 200, body: hcard_html)
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
|
|
@ -88,66 +91,150 @@ module DiasporaFederation
|
||||||
callback_person = person
|
callback_person = person
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Discovery::Discovery.new(account).fetch_and_save).to be(callback_person)
|
expect(subject.fetch_and_save).to be(callback_person)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "falls back to http if https fails with 404" do
|
it "falls back to http if https fails with 404" do
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 404)
|
.to_return(status: 404)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
.to_return(status: 200, body: webfinger_jrd)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
|
||||||
.to_return(status: 200, body: webfinger_xrd)
|
|
||||||
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
.to_return(status: 200, body: hcard_html)
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
person = Discovery::Discovery.new(account).fetch_and_save
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
expect(person.guid).to eq(alice.guid)
|
expect(person.guid).to eq(alice.guid)
|
||||||
expect(person.diaspora_id).to eq(account)
|
expect(person.diaspora_id).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "falls back to http if https fails with ssl error" do
|
it "falls back to http if https fails with ssl error" do
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_raise(OpenSSL::SSL::SSLError)
|
.to_raise(OpenSSL::SSL::SSLError)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
.to_return(status: 200, body: webfinger_jrd)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
|
||||||
.to_return(status: 200, body: webfinger_xrd)
|
|
||||||
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
.to_return(status: 200, body: hcard_html)
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
person = Discovery::Discovery.new(account).fetch_and_save
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
expect(person.guid).to eq(alice.guid)
|
expect(person.guid).to eq(alice.guid)
|
||||||
expect(person.diaspora_id).to eq(account)
|
expect(person.diaspora_id).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails if the diaspora* ID does not match" do
|
it "fails if the diaspora* ID does not match" do
|
||||||
modified_webfinger = webfinger_xrd.gsub(account, "anonther_user@example.com")
|
modified_webfinger = webfinger_jrd.gsub(account, "anonther_user@example.com")
|
||||||
|
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
|
||||||
.to_return(status: 200, body: modified_webfinger)
|
.to_return(status: 200, body: modified_webfinger)
|
||||||
|
|
||||||
expect { Discovery::Discovery.new(account).fetch_and_save }.to raise_error Discovery::DiscoveryError
|
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails if the diaspora* ID was not found" do
|
it "fails if the diaspora* ID was not found" do
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 404)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 404)
|
||||||
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
||||||
.to_return(status: 200, body: host_meta_xrd)
|
.to_return(status: 200, body: host_meta_xrd)
|
||||||
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
||||||
.to_return(status: 404)
|
.to_return(status: 404)
|
||||||
|
|
||||||
expect { Discovery::Discovery.new(account).fetch_and_save }.to raise_error Discovery::DiscoveryError
|
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
|
||||||
|
end
|
||||||
|
|
||||||
|
context "legacy WebFinger" do
|
||||||
|
it "falls back to legacy WebFinger" do
|
||||||
|
incomplete_webfinger_json = "{\"links\":[{\"rel\":\"http://openid.net/specs/connect/1.0/issuer\"," \
|
||||||
|
"\"href\":\"https://localhost:3000/\"}],\"subject\":\"acct:#{account}\"}"
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: incomplete_webfinger_json)
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_return(status: 200, body: host_meta_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: webfinger_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
|
expect(person.guid).to eq(alice.guid)
|
||||||
|
expect(person.diaspora_id).to eq(account)
|
||||||
|
expect(person.url).to eq(alice.url)
|
||||||
|
expect(person.exported_key).to eq(alice.serialized_public_key)
|
||||||
|
|
||||||
|
profile = person.profile
|
||||||
|
|
||||||
|
expect(profile.diaspora_id).to eq(alice.diaspora_id)
|
||||||
|
expect(profile.first_name).to eq("Dummy")
|
||||||
|
expect(profile.last_name).to eq("User")
|
||||||
|
|
||||||
|
expect(profile.image_url).to eq(default_image)
|
||||||
|
expect(profile.image_url_medium).to eq(default_image)
|
||||||
|
expect(profile.image_url_small).to eq(default_image)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "falls back to http if https fails with 404" do
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 404)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 404)
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_return(status: 404)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_return(status: 200, body: host_meta_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: webfinger_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
|
expect(person.guid).to eq(alice.guid)
|
||||||
|
expect(person.diaspora_id).to eq(account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "falls back to http if https fails with ssl error" do
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_raise(OpenSSL::SSL::SSLError)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: "foobar")
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_raise(OpenSSL::SSL::SSLError)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_return(status: 200, body: host_meta_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: webfinger_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
|
||||||
|
.to_return(status: 200, body: hcard_html)
|
||||||
|
|
||||||
|
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
|
||||||
|
person = subject.fetch_and_save
|
||||||
|
|
||||||
|
expect(person.guid).to eq(alice.guid)
|
||||||
|
expect(person.diaspora_id).to eq(account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails if the diaspora* ID does not match" do
|
||||||
|
modified_webfinger = webfinger_xrd.gsub(account, "anonther_user@example.com")
|
||||||
|
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: "foobar")
|
||||||
|
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
|
||||||
|
.to_return(status: 200, body: host_meta_xrd)
|
||||||
|
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
|
||||||
|
.to_return(status: 200, body: modified_webfinger)
|
||||||
|
|
||||||
|
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "error handling" do
|
context "error handling" do
|
||||||
subject { Discovery::Discovery.new(account) }
|
|
||||||
|
|
||||||
it "re-raises DiscoveryError" do
|
it "re-raises DiscoveryError" do
|
||||||
expect(subject).to receive(:validate_diaspora_id)
|
expect(subject).to receive(:validate_diaspora_id)
|
||||||
.and_raise(Discovery::DiscoveryError, "Something went wrong!")
|
.and_raise(Discovery::DiscoveryError, "Something went wrong!")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue