Remove legacy Webfinger handling

This commit is contained in:
Benjamin Neff 2021-11-27 02:14:41 +01:00
parent 3861eb9fef
commit d5107f5678
No known key found for this signature in database
GPG key ID: 971464C3F1A90194
12 changed files with 341 additions and 767 deletions

View file

@ -5,20 +5,6 @@ require_dependency "diaspora_federation/application_controller"
module DiasporaFederation
# This controller handles all webfinger-specific requests.
class WebfingerController < ApplicationController
# Returns the host-meta xml
#
# example:
# <?xml version="1.0" encoding="UTF-8"?>
# <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
# <Link rel="lrdd" type="application/xrd+xml"
# template="https://server.example/.well-known/webfinger.xml?resource={uri}"/>
# </XRD>
#
# GET /.well-known/host-meta
def host_meta
render xml: WebfingerController.host_meta_xml, content_type: "application/xrd+xml"
end
# Returns the webfinger as RFC 7033 JRD or XRD.
#
# JSON example:
@ -59,20 +45,6 @@ module DiasporaFederation
# ]
# }
#
# XML example:
# <?xml version="1.0" encoding="UTF-8"?>
# <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
# <Subject>acct:alice@localhost:3000</Subject>
# <Alias>http://localhost:3000/people/c8e87290f6a20132963908fbffceb188</Alias>
# <Link rel="http://microformats.org/profile/hcard" type="text/html"
# href="http://localhost:3000/hcard/users/c8e87290f6a20132963908fbffceb188"/>
# <Link rel="http://joindiaspora.com/seed_location" type="text/html" href="http://localhost:3000/"/>
# <Link rel="http://webfinger.net/rel/profile-page" type="text/html" href="http://localhost:3000/u/alice"/>
# <Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml"
# href="http://localhost:3000/public/alice.atom"/>
# <Link rel="salmon" href="http://localhost:3000/receive/users/c8e87290f6a20132963908fbffceb188"/>
# </XRD>
#
# GET /.well-known/webfinger?resource=<uri>
def webfinger
person_wf = find_person_webfinger(params.require(:resource))
@ -80,26 +52,13 @@ module DiasporaFederation
if person_wf.nil?
head :not_found
else
logger.info "webfinger profile request for: #{person_wf.acct_uri}"
logger.info "Webfinger profile request for: #{person_wf.acct_uri}"
respond_to do |format|
format.any(:jrd, :json, :html) do
headers["Access-Control-Allow-Origin"] = "*"
render json: JSON.pretty_generate(person_wf.to_json), content_type: "application/jrd+json"
end
format.any(:xrd, :xml) do
render xml: person_wf.to_xml, content_type: "application/xrd+xml"
end
end
headers["Access-Control-Allow-Origin"] = "*"
render json: JSON.pretty_generate(person_wf.to_json), content_type: "application/jrd+json"
end
end
# Creates the host-meta xml with the configured server_uri and caches it
# @return [String] XML string
def self.host_meta_xml
@host_meta_xml ||= Discovery::HostMeta.from_base_url(DiasporaFederation.server_uri.to_s).to_xml
end
private
def find_person_webfinger(query)

View file

@ -11,7 +11,6 @@ DiasporaFederation::Engine.routes.draw do
end
controller :webfinger do
get ".well-known/host-meta" => :host_meta, :as => "host_meta"
get ".well-known/webfinger" => :webfinger, :as => "webfinger"
end

View file

@ -10,7 +10,6 @@ end
require "diaspora_federation/discovery/exceptions"
require "diaspora_federation/discovery/xrd_document"
require "diaspora_federation/discovery/host_meta"
require "diaspora_federation/discovery/web_finger"
require "diaspora_federation/discovery/h_card"
require "diaspora_federation/discovery/discovery"

View file

@ -24,7 +24,7 @@ module DiasporaFederation
validate_diaspora_id
DiasporaFederation.callbacks.trigger(:save_person_after_webfinger, person)
logger.info "successfully webfingered #{diaspora_id}"
logger.info "Successfully webfingered #{diaspora_id}"
person
rescue DiscoveryError
raise # simply re-raise DiscoveryError
@ -67,22 +67,11 @@ module DiasporaFederation
"acct:#{diaspora_id}"
end
def legacy_webfinger_url_from_host_meta
# This tries the xrd url with https first, then falls back to http.
host_meta = HostMeta.from_xml(get("https://#{domain}/.well-known/host-meta", http_fallback: true))
host_meta.webfinger_template_url.gsub("{uri}", acct_parameter)
end
def webfinger
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 if webfinger_http_fallback is enabled.
@webfinger = WebFinger.from_json(get(webfinger_url, http_fallback: DiasporaFederation.webfinger_http_fallback))
rescue => e # rubocop:disable Style/RescueStandardError
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))
@webfinger ||=
WebFinger.from_json(get("https://#{domain}/.well-known/webfinger?resource=#{acct_parameter}",
http_fallback: DiasporaFederation.webfinger_http_fallback))
end
def hcard

View file

@ -1,92 +0,0 @@
# frozen_string_literal: true
module DiasporaFederation
module Discovery
# Generates and parses Host Meta documents.
#
# This is a minimal implementation of the standard, only to the degree of what
# is used for the purposes of the diaspora* protocol. (e.g. WebFinger)
#
# @example Creating a Host Meta document
# doc = HostMeta.from_base_url("https://pod.example.tld/")
# doc.to_xml
#
# @example Parsing a Host Meta document
# doc = HostMeta.from_xml(xml_string)
# webfinger_tpl = doc.webfinger_template_url
#
# @see http://tools.ietf.org/html/rfc6415 RFC 6415: "Web Host Metadata"
# @see XrdDocument
class HostMeta
private_class_method :new
# Creates a new host-meta instance
# @param [String] webfinger_url the webfinger-url
def initialize(webfinger_url)
@webfinger_url = webfinger_url
end
# URL fragment to append to the base URL
WEBFINGER_SUFFIX = "/.well-known/webfinger.xml?resource={uri}"
# Returns the WebFinger URL that was used to build this instance (either from
# xml or by giving a base URL).
# @return [String] WebFinger template URL
def webfinger_template_url
@webfinger_url
end
# Produces the XML string for the Host Meta instance with a +Link+ element
# containing the +webfinger_url+.
# @return [String] XML string
def to_xml
doc = XrdDocument.new
doc.links << {rel: "lrdd",
type: "application/xrd+xml",
template: @webfinger_url}
doc.to_xml
end
# Builds a new HostMeta instance and constructs the WebFinger URL from the
# given base URL by appending HostMeta::WEBFINGER_SUFFIX.
# @param [String, URL] base_url the base-url for the webfinger-url
# @return [HostMeta]
# @raise [InvalidData] if the webfinger url is malformed
def self.from_base_url(base_url)
webfinger_url = "#{base_url.to_s.chomp('/')}#{WEBFINGER_SUFFIX}"
raise InvalidData, "invalid webfinger url: #{webfinger_url}" unless webfinger_url_valid?(webfinger_url)
new(webfinger_url)
end
# Reads the given Host Meta XML document string and populates the
# +webfinger_url+.
# @param [String] hostmeta_xml Host Meta XML string
# @raise [InvalidData] if the xml or the webfinger url is malformed
def self.from_xml(hostmeta_xml)
data = XrdDocument.xml_data(hostmeta_xml)
raise InvalidData, "received an invalid xml" unless data.key?(:links)
webfinger_url = webfinger_url_from_xrd(data)
raise InvalidData, "invalid webfinger url: #{webfinger_url}" unless webfinger_url_valid?(webfinger_url)
new(webfinger_url)
end
# Applies some basic sanity-checking to the given URL
# @param [String] url validation subject
# @return [Boolean] validation result
private_class_method def self.webfinger_url_valid?(url)
!url.nil? && url.instance_of?(String) && url =~ %r{\Ahttps?://.*/.*\{uri\}.*}i
end
# Gets the webfinger url from an XRD data structure
# @param [Hash] data extracted data
# @return [String] webfinger url
private_class_method def self.webfinger_url_from_xrd(data)
link = data[:links].find {|l| l[:rel] == "lrdd" }
return link[:template] unless link.nil?
end
end
end
end

View file

@ -3,10 +3,7 @@
module DiasporaFederation
module Discovery
# The WebFinger document used for diaspora* user discovery is based on an
# {http://tools.ietf.org/html/draft-jones-appsawg-webfinger older draft of the specification}.
#
# In the meantime an actual RFC draft has been in development, which should
# serve as a base for all future changes of this implementation.
# {https://datatracker.ietf.org/doc/html/rfc7033 RFC 7033}.
#
# @example Creating a WebFinger document from a person hash
# wf = WebFinger.new(
@ -17,22 +14,20 @@ module DiasporaFederation
# atom_url: "https://server.example/public/user.atom",
# salmon_url: "https://server.example/receive/users/0123456789abcdef"
# )
# xml_string = wf.to_xml
# json_string = wf.to_json
#
# @example Creating a WebFinger instance from an xml document
# wf = WebFinger.from_xml(xml_string)
# @example Creating a WebFinger instance from an JSON document
# wf = WebFinger.from_json(json_string)
# ...
# hcard_url = wf.hcard_url
# ...
#
# @see http://tools.ietf.org/html/draft-jones-appsawg-webfinger "WebFinger" -
# current draft
# @see http://www.iana.org/assignments/link-relations/link-relations.xhtml
# official list of IANA link relations
class WebFinger < Entity
# @!attribute [r] acct_uri
# The Subject element should contain the webfinger address that was asked
# for. If it does not, then this webfinger profile MUST be ignored.
# The Subject element should contain the WebFinger address that was asked
# for. If it does not, then this WebFinger profile MUST be ignored.
# @return [String]
property :acct_uri, :string
@ -67,7 +62,7 @@ module DiasporaFederation
property :salmon_url, :string, optional: true
# @!attribute [r] subscribe_url
# This url is used to find another user on the home-pod of the user in the webfinger.
# This url is used to find another user on the home-pod of the user in the WebFinger.
property :subscribe_url, :string, optional: true
# +hcard_url+ link relation
@ -106,29 +101,29 @@ module DiasporaFederation
super(data)
end
# Creates the XML string from the current WebFinger instance
# @return [String] XML string
# @!visibility private
# Generating WebFinger to XML is not supported anymore, use {#to_json} instead.
def to_xml
to_xrd.to_xml
raise "Generating WebFinger to XML is not supported anymore, use 'to_json' instead."
end
# Creates the JSON string from the current WebFinger instance
# @return [String] JSON string
def to_json(*_args)
to_xrd.to_json
end
# Creates a WebFinger instance from the given XML string
# @param [String] webfinger_xml WebFinger XML string
# @return [WebFinger] WebFinger instance
# @raise [InvalidData] if the given XML string is invalid or incomplete
def self.from_xml(webfinger_xml)
from_hash(parse_xml_and_validate(webfinger_xml))
# @!visibility private
# Parsing WebFinger as XML is not supported anymore, use {from_json} instead.
def self.from_xml(_webfinger_xml)
raise "Parsing WebFinger as XML is not supported anymore, use 'from_json' instead."
end
# Creates a WebFinger instance from the given JSON string
# @param [String] webfinger_json WebFinger JSON string
# @return [WebFinger] WebFinger instance
def self.from_json(webfinger_json)
from_hash(XrdDocument.json_data(webfinger_json))
from_hash(parse_json_and_validate(webfinger_json))
end
# Creates a WebFinger instance from the given data
@ -157,15 +152,15 @@ module DiasporaFederation
private
# Parses the XML string to a Hash and does some rudimentary checking on
# Parses the JSON string to a Hash and does some rudimentary checking on
# the data Hash.
# @param [String] webfinger_xml WebFinger XML string
# @return [Hash] data XML data
# @raise [InvalidData] if the given XML string is invalid or incomplete
private_class_method def self.parse_xml_and_validate(webfinger_xml)
XrdDocument.xml_data(webfinger_xml).tap do |data|
# @param [String] webfinger_json WebFinger JSON string
# @return [Hash] data JSON data
# @raise [InvalidData] if the given JSON string is invalid or incomplete
private_class_method def self.parse_json_and_validate(webfinger_json)
XrdDocument.json_data(webfinger_json).tap do |data|
valid = data.key?(:subject) && data.key?(:links)
raise InvalidData, "webfinger xml is incomplete" unless valid
raise InvalidData, "Webfinger JSON is incomplete" unless valid
end
end

View file

@ -5,13 +5,9 @@ module DiasporaFederation
# This class implements basic handling of XRD documents as far as it is
# necessary in the context of the protocols used with diaspora* federation.
#
# @note {http://tools.ietf.org/html/rfc6415 RFC 6415} recommends that servers
# should also offer the JRD format in addition to the XRD representation.
# Implementing +XrdDocument#to_json+ and +XrdDocument.json_data+ should
# be almost trivial due to the simplicity of the format and the way the data
# is stored internally already. See
# {http://tools.ietf.org/html/rfc6415#appendix-A RFC 6415, Appendix A}
# for a description of the JSON format.
# It also implements handling of the JRD format, see
# {https://datatracker.ietf.org/doc/html/rfc6415#appendix-A RFC 6415, Appendix A}
# for a description of the JSON format.
#
# @example Creating a XrdDocument
# doc = XrdDocument.new
@ -210,7 +206,7 @@ module DiasporaFederation
# symbolize link keys from JSON hash, but only convert known keys
private_class_method def self.symbolize_keys_for_links(links)
links.map do |link|
links&.map do |link|
{}.tap do |hash|
LINK_ATTRS.each do |attr|
hash[attr] = link[attr.to_s] if link.key?(attr.to_s)

View file

@ -4,39 +4,6 @@ module DiasporaFederation
describe WebfingerController, type: :controller do
routes { DiasporaFederation::Engine.routes }
describe "GET #host_meta" do
before do
DiasporaFederation.server_uri = URI("http://localhost:3000/")
WebfingerController.instance_variable_set(:@host_meta_xml, nil) # clear cache
end
it "succeeds" do
get :host_meta
expect(response).to be_successful
end
it "contains the webfinger-template" do
get :host_meta
expect(response.body).to include "template=\"http://localhost:3000/.well-known/webfinger.xml?resource={uri}\""
end
it "returns a application/xrd+xml" do
get :host_meta
expect(response.header["Content-Type"]).to include "application/xrd+xml"
end
it "calls Discovery::HostMeta.from_base_url with the base url" do
expect(Discovery::HostMeta).to receive(:from_base_url).with("http://localhost:3000/").and_call_original
get :host_meta
end
it "caches the xml" do
expect(Discovery::HostMeta).to receive(:from_base_url).exactly(1).times.and_call_original
get :host_meta
get :host_meta
end
end
describe "GET #webfinger" do
it "uses the JRD format as default" do
get :webfinger, params: {resource: alice.diaspora_id}
@ -44,81 +11,46 @@ module DiasporaFederation
expect(response.header["Content-Type"]).to include "application/jrd+json"
end
context "json", exceptions: :catch do
it "succeeds when the person exists" do
get :webfinger, format: :json, params: {resource: alice.diaspora_id}
expect(response).to be_successful
end
it "succeeds with 'acct:' in the query when the person exists" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response).to be_successful
end
it "contains the diaspora* ID" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.body).to include "\"subject\": \"acct:alice@localhost:3000\""
end
it "returns a application/jrd+json" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.header["Content-Type"]).to include "application/jrd+json"
end
it "adds a Access-Control-Allow-Origin header" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.header["Access-Control-Allow-Origin"]).to eq("*")
end
it "404s when the person does not exist" do
get :webfinger, format: :json, params: {resource: "me@mydiaspora.pod.com"}
expect(response).to be_not_found
end
it "raises when the resource parameter is missing" do
expect {
get :webfinger, format: :json
}.to raise_error ActionController::ParameterMissing, /param is missing or the value is empty: resource/
end
it "calls the fetch_person_for_webfinger callback" do
expect_callback(:fetch_person_for_webfinger, "alice@localhost:3000").and_call_original
get :webfinger, format: :json, params: {resource: "acct:alice@localhost:3000"}
end
it "succeeds when the person exists" do
get :webfinger, format: :json, params: {resource: alice.diaspora_id}
expect(response).to be_successful
end
context "xml" do
it "succeeds when the person exists" do
get :webfinger, format: :json, params: {resource: alice.diaspora_id}
expect(response).to be_successful
end
it "succeeds with 'acct:' in the query when the person exists" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response).to be_successful
end
it "succeeds with 'acct:' in the query when the person exists" do
get :webfinger, format: :xml, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response).to be_successful
end
it "contains the diaspora* ID" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.body).to include "\"subject\": \"acct:alice@localhost:3000\""
end
it "contains the diaspora* ID" do
get :webfinger, format: :xml, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.body).to include "<Subject>acct:alice@localhost:3000</Subject>"
end
it "returns a application/jrd+json" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.header["Content-Type"]).to include "application/jrd+json"
end
it "returns a application/xrd+xml" do
get :webfinger, format: :xml, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.header["Content-Type"]).to include "application/xrd+xml"
end
it "adds a Access-Control-Allow-Origin header" do
get :webfinger, format: :json, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response.header["Access-Control-Allow-Origin"]).to eq("*")
end
it "404s when the person does not exist" do
get :webfinger, format: :xml, params: {resource: "me@mydiaspora.pod.com"}
expect(response).to be_not_found
end
it "404s when the person does not exist" do
get :webfinger, format: :json, params: {resource: "me@mydiaspora.pod.com"}
expect(response).to be_not_found
end
it "calls the fetch_person_for_webfinger callback" do
expect_callback(:fetch_person_for_webfinger, "alice@localhost:3000").and_call_original
it "raises when the resource parameter is missing" do
expect {
get :webfinger, format: :json
}.to raise_error ActionController::ParameterMissing, /param is missing or the value is empty: resource/
end
get :webfinger, format: :xml, params: {resource: "acct:alice@localhost:3000"}
end
it "calls the fetch_person_for_webfinger callback" do
expect_callback(:fetch_person_for_webfinger, "alice@localhost:3000").and_call_original
get :webfinger, format: :json, params: {resource: "acct:alice@localhost:3000"}
end
end
end

View file

@ -2,7 +2,8 @@
module DiasporaFederation
describe Discovery::Discovery do
let(:host_meta_xrd) { Discovery::HostMeta.from_base_url("http://localhost:3000/").to_xml }
subject(:discovery) { Discovery::Discovery.new(account) }
let(:webfinger_data) {
{
acct_uri: "acct:#{alice.diaspora_id}",
@ -17,9 +18,6 @@ module DiasporaFederation
public_key: alice.serialized_public_key
}
}
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)
}
@ -40,7 +38,6 @@ module DiasporaFederation
}
let(:account) { alice.diaspora_id }
let(:default_image) { "http://localhost:3000/assets/user/default.png" }
subject { Discovery::Discovery.new(account) }
describe "#intialize" do
it "sets diaspora* ID" do
@ -62,7 +59,7 @@ module DiasporaFederation
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
person = discovery.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
@ -93,7 +90,7 @@ module DiasporaFederation
callback_person = person
end
expect(subject.fetch_and_save).to be(callback_person)
expect(discovery.fetch_and_save).to be(callback_person)
end
it "fails if the diaspora* ID does not match" do
@ -102,67 +99,32 @@ module DiasporaFederation
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: modified_webfinger)
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
expect { discovery.fetch_and_save }.to raise_error Discovery::DiscoveryError
end
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")
.to_return(status: 200, body: host_meta_xrd)
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
.to_return(status: 404)
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
expect { discovery.fetch_and_save }.to raise_error Discovery::DiscoveryError
end
context "http fallback" do
context "http fallback disabled (default)" do
it "falls back to legacy WebFinger 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, "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)
end
it "falls back to legacy WebFinger if https fails with ssl error" do
context "with http fallback" do
context "when http fallback disabled (default)" do
it "does not fall 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, "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)
expect { discovery.fetch_and_save }.to raise_error Discovery::DiscoveryError
end
end
context "http fallback enabled" do
before :all do
context "when http fallback enabled" do
before do
DiasporaFederation.webfinger_http_fallback = true
end
after :all do
after do
DiasporaFederation.webfinger_http_fallback = false
end
@ -175,7 +137,7 @@ module DiasporaFederation
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
person = discovery.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
@ -190,7 +152,7 @@ module DiasporaFederation
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
person = discovery.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
@ -198,118 +160,33 @@ module DiasporaFederation
end
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, "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, "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
context "error handling" do
context "with error handling" do
it "re-raises DiscoveryError" do
expect(subject).to receive(:validate_diaspora_id)
expect(discovery).to receive(:validate_diaspora_id)
.and_raise(Discovery::DiscoveryError, "Something went wrong!")
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError, "Something went wrong!"
expect { discovery.fetch_and_save }.to raise_error Discovery::DiscoveryError, "Something went wrong!"
end
it "re-raises InvalidDocument" do
expect(subject).to receive(:validate_diaspora_id)
expect(discovery).to receive(:validate_diaspora_id)
.and_raise(Discovery::InvalidDocument, "Wrong document!")
expect { subject.fetch_and_save }.to raise_error Discovery::InvalidDocument, "Wrong document!"
expect { discovery.fetch_and_save }.to raise_error Discovery::InvalidDocument, "Wrong document!"
end
it "re-raises InvalidData" do
expect(subject).to receive(:validate_diaspora_id)
expect(discovery).to receive(:validate_diaspora_id)
.and_raise(Discovery::InvalidData, "Wrong data!")
expect { subject.fetch_and_save }.to raise_error Discovery::InvalidData, "Wrong data!"
expect { discovery.fetch_and_save }.to raise_error Discovery::InvalidData, "Wrong data!"
end
it "raises a DiscoveryError when an unhandled error occurs" do
expect(subject).to receive(:validate_diaspora_id)
.and_raise("OMG! EVERYTHING IS BROKEN!")
allow(discovery).to receive(:validate_diaspora_id).and_raise("OMG! EVERYTHING IS BROKEN!")
expect {
subject.fetch_and_save
discovery.fetch_and_save
}.to raise_error Discovery::DiscoveryError,
"Failed discovery for #{account}: RuntimeError: OMG! EVERYTHING IS BROKEN!"
end

View file

@ -1,103 +0,0 @@
# frozen_string_literal: true
module DiasporaFederation
describe Discovery::HostMeta do
let(:base_url) { "https://pod.example.tld/" }
let(:xml) { <<~XML }
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/xrd+xml" template="#{base_url}.well-known/webfinger.xml?resource={uri}"/>
</XRD>
XML
it "must not create blank instances" do
expect { Discovery::HostMeta.new }.to raise_error NoMethodError
end
context "generation" do
it "creates a nice XML document" do
hm = Discovery::HostMeta.from_base_url(base_url)
expect(hm.to_xml).to eq(xml)
end
it "converts object to string" do
hm = Discovery::HostMeta.from_base_url(URI(base_url))
expect(hm.to_xml).to eq(xml)
end
it "appends a '/' if necessary" do
hm = Discovery::HostMeta.from_base_url("https://pod.example.tld")
expect(hm.to_xml).to eq(xml)
end
it "fails if the base_url was omitted" do
expect { Discovery::HostMeta.from_base_url("") }.to raise_error Discovery::InvalidData
end
end
context "parsing" do
it "parses its own output" do
hm = Discovery::HostMeta.from_xml(xml)
expect(hm.webfinger_template_url).to eq("#{base_url}.well-known/webfinger.xml?resource={uri}")
end
it "also reads old-style XML" do
historic_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<!-- Resource-specific Information -->
<Link rel="lrdd"
type="application/xrd+xml"
template="#{base_url}webfinger?q={uri}" />
</XRD>
XML
hm = Discovery::HostMeta.from_xml(historic_xml)
expect(hm.webfinger_template_url).to eq("#{base_url}webfinger?q={uri}")
end
it "also reads friendica/redmatrix XML" do
friendica_redmatrix_xml = <<~XML
<?xml version='1.0' encoding='UTF-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'
xmlns:hm='http://host-meta.net/xrd/1.0'>
<hm:Host>pod.example.tld</hm:Host>
<Link rel='lrdd' template='#{base_url}xrd/?uri={uri}' />
<Link rel="http://oexchange.org/spec/0.8/rel/resident-target" type="application/xrd+xml"
href="https://pod.example.tld/oexchange/xrd" />
</XRD>
XML
hm = Discovery::HostMeta.from_xml(friendica_redmatrix_xml)
expect(hm.webfinger_template_url).to eq("#{base_url}xrd/?uri={uri}")
end
it "fails if the document does not contain a webfinger url" do
invalid_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
</XRD>
XML
expect { Discovery::HostMeta.from_xml(invalid_xml) }.to raise_error Discovery::InvalidData
end
it "fails if the document contains a malformed webfinger url" do
invalid_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/xrd+xml" template="#{base_url}webfinger?q="/>
</XRD>
XML
expect { Discovery::HostMeta.from_xml(invalid_xml) }.to raise_error Discovery::InvalidData
end
it "fails if the document is invalid" do
expect { Discovery::HostMeta.from_xml("") }.to raise_error Discovery::InvalidDocument
end
end
end
end

View file

@ -18,29 +18,6 @@ module DiasporaFederation
}
}
let(:xml) { <<~XML }
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>#{acct}</Subject>
<Alias>#{person.alias_url}</Alias>
<Link rel="http://microformats.org/profile/hcard" type="text/html" href="#{person.hcard_url}"/>
<Link rel="http://joindiaspora.com/seed_location" type="text/html" href="#{person.url}"/>
<Link rel="http://webfinger.net/rel/profile-page" type="text/html" href="#{person.profile_url}"/>
<Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="#{person.atom_url}"/>
<Link rel="salmon" href="#{person.salmon_url}"/>
<Link rel="http://ostatus.org/schema/1.0/subscribe" template="#{person.subscribe_url}"/>
</XRD>
XML
let(:minimal_xml) { <<~XML }
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>#{acct}</Subject>
<Link rel="http://microformats.org/profile/hcard" type="text/html" href="#{person.hcard_url}"/>
<Link rel="http://joindiaspora.com/seed_location" type="text/html" href="#{person.url}"/>
</XRD>
XML
let(:json) { <<~JSON }
{
"subject": "#{acct}",
@ -74,7 +51,7 @@ module DiasporaFederation
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "http://somehost:3000/people?q={uri}"
"template": "#{person.url}people?q={uri}"
}
]
}
@ -102,7 +79,7 @@ module DiasporaFederation
it_behaves_like "an Entity subclass"
context "generation" do
context "when generating" do
let(:minimal_data) { {acct_uri: acct, hcard_url: person.hcard_url, seed_url: person.url} }
let(:additional_data) {
{
@ -120,113 +97,66 @@ module DiasporaFederation
}
}
context "xml" do
it "creates a nice XML document" do
wf = Discovery::WebFinger.new(data, aliases: [person.alias_url])
expect(wf.to_xml).to eq(xml)
end
it "creates minimal XML document" do
wf = Discovery::WebFinger.new(minimal_data)
expect(wf.to_xml).to eq(minimal_xml)
end
it "creates XML document with additional data" do
xml_with_additional_data = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>#{acct}</Subject>
<Alias>#{person.alias_url}</Alias>
<Alias>#{person.profile_url}</Alias>
<Property type="http://webfinger.example/ns/name">Bob Smith</Property>
<Link rel="http://microformats.org/profile/hcard" type="text/html" href="#{person.hcard_url}"/>
<Link rel="http://joindiaspora.com/seed_location" type="text/html" href="#{person.url}"/>
<Link rel="http://portablecontacts.net/spec/1.0" href="https://pod.example.tld/poco/trouble"/>
<Link rel="http://webfinger.net/rel/avatar" type="image/jpeg" href="http://localhost:3000/assets/user/default.png"/>
<Link rel="http://openid.net/specs/connect/1.0/issuer" href="https://pod.example.tld/"/>
</XRD>
XML
wf = Discovery::WebFinger.new(minimal_data, additional_data)
expect(wf.to_xml).to eq(xml_with_additional_data)
end
it "creates a nice JSON document" do
wf = Discovery::WebFinger.new(data, aliases: [person.alias_url])
expect(JSON.pretty_generate(wf.to_json)).to eq(json.strip)
end
context "json" do
it "creates a nice JSON document" do
wf = Discovery::WebFinger.new(data, aliases: [person.alias_url])
expect(JSON.pretty_generate(wf.to_json)).to eq(json.strip)
end
it "creates minimal JSON document" do
wf = Discovery::WebFinger.new(minimal_data)
expect(JSON.pretty_generate(wf.to_json)).to eq(minimal_json.strip)
end
it "creates minimal JSON document" do
wf = Discovery::WebFinger.new(minimal_data)
expect(JSON.pretty_generate(wf.to_json)).to eq(minimal_json.strip)
end
it "creates JSON document with additional data" do
json_with_additional_data = <<~JSON
{
"subject": "#{acct}",
"aliases": [
"#{person.alias_url}",
"#{person.profile_url}"
],
"properties": {
"http://webfinger.example/ns/name": "Bob Smith"
it "creates JSON document with additional data" do
json_with_additional_data = <<~JSON
{
"subject": "#{acct}",
"aliases": [
"#{person.alias_url}",
"#{person.profile_url}"
],
"properties": {
"http://webfinger.example/ns/name": "Bob Smith"
},
"links": [
{
"rel": "http://microformats.org/profile/hcard",
"type": "text/html",
"href": "#{person.hcard_url}"
},
"links": [
{
"rel": "http://microformats.org/profile/hcard",
"type": "text/html",
"href": "#{person.hcard_url}"
},
{
"rel": "http://joindiaspora.com/seed_location",
"type": "text/html",
"href": "#{person.url}"
},
{
"rel": "http://portablecontacts.net/spec/1.0",
"href": "https://pod.example.tld/poco/trouble"
},
{
"rel": "http://webfinger.net/rel/avatar",
"type": "image/jpeg",
"href": "http://localhost:3000/assets/user/default.png"
},
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://pod.example.tld/"
}
]
}
JSON
{
"rel": "http://joindiaspora.com/seed_location",
"type": "text/html",
"href": "#{person.url}"
},
{
"rel": "http://portablecontacts.net/spec/1.0",
"href": "https://pod.example.tld/poco/trouble"
},
{
"rel": "http://webfinger.net/rel/avatar",
"type": "image/jpeg",
"href": "http://localhost:3000/assets/user/default.png"
},
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://pod.example.tld/"
}
]
}
JSON
wf = Discovery::WebFinger.new(minimal_data, additional_data)
expect(JSON.pretty_generate(wf.to_json)).to eq(json_with_additional_data.strip)
end
wf = Discovery::WebFinger.new(minimal_data, additional_data)
expect(JSON.pretty_generate(wf.to_json)).to eq(json_with_additional_data.strip)
end
it "does not support XML anymore" do
expect { Discovery::WebFinger.new(minimal_data).to_xml }
.to raise_error "Generating WebFinger to XML is not supported anymore, use 'to_json' instead."
end
end
context "parsing" do
it "reads its own xml output" do
wf = Discovery::WebFinger.from_xml(xml)
expect(wf.acct_uri).to eq(acct)
expect(wf.hcard_url).to eq(person.hcard_url)
expect(wf.seed_url).to eq(person.url)
expect(wf.profile_url).to eq(person.profile_url)
expect(wf.atom_url).to eq(person.atom_url)
expect(wf.salmon_url).to eq(person.salmon_url)
expect(wf.subscribe_url).to eq(person.subscribe_url)
end
it "reads minimal xml" do
wf = Discovery::WebFinger.from_xml(minimal_xml)
expect(wf.acct_uri).to eq(acct)
expect(wf.hcard_url).to eq(person.hcard_url)
expect(wf.seed_url).to eq(person.url)
end
context "when parsing" do
it "reads its own json output" do
wf = Discovery::WebFinger.from_json(json)
expect(wf.acct_uri).to eq(acct)
@ -246,119 +176,219 @@ module DiasporaFederation
end
it "is frozen after parsing" do
wf = Discovery::WebFinger.from_xml(xml)
wf = Discovery::WebFinger.from_json(json)
expect(wf).to be_frozen
end
it "reads friendica XML (two aliases, first with acct)" do
friendica_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
it "reads friendica JSON" do
friendica_hcard_url = "#{person.url}hcard/#{person.nickname}"
friendica_profile_url = "#{person.url}profile/#{person.nickname}"
friendica_atom_url = "#{person.url}dfrn_poll/#{person.nickname}"
friendica_salmon_url = "#{person.url}salmon/#{person.nickname}"
friendica_subscribe_url = "#{person.url}follow?url={uri}"
<Subject>#{acct}</Subject>
<Alias>#{acct}</Alias>
<Alias>#{person.alias_url}</Alias>
friendica_json = <<~JSON
{
"subject": "#{acct}",
"aliases": [
"#{person.url}~#{person.nickname}",
"#{friendica_profile_url}"
],
"links": [
{
"rel": "http://purl.org/macgirvin/dfrn/1.0",
"href": "#{person.url}profile/#{person.nickname}"
},
{
"rel": "http://schemas.google.com/g/2010#updates-from",
"type": "application/atom+xml",
"href": "#{friendica_atom_url}"
},
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "#{friendica_profile_url}"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "#{friendica_profile_url}"
},
{
"rel": "http://microformats.org/profile/hcard",
"type": "text/html",
"href": "#{friendica_hcard_url}"
},
{
"rel": "http://portablecontacts.net/spec/1.0",
"href": "#{person.url}poco/#{person.nickname}"
},
{
"rel": "http://webfinger.net/rel/avatar",
"type": "image/png",
"href": "#{person.url}photo/profile/#{person.nickname}.png"
},
{
"rel": "http://joindiaspora.com/seed_location",
"type": "text/html",
"href": "#{person.url}"
},
{
"rel": "salmon",
"href": "#{friendica_salmon_url}"
},
{
"rel": "http://salmon-protocol.org/ns/salmon-replies",
"href": "#{friendica_salmon_url}"
},
{
"rel": "http://salmon-protocol.org/ns/salmon-mention",
"href": "#{friendica_salmon_url}/mention"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "#{person.url}follow?url={uri}"
},
{
"rel": "magic-public-key",
"href": "data:application/magic-public-key,RSA.abcdef1234567890"
},
{
"rel": "http://purl.org/openwebauth/v1",
"type": "application/x-zot+json",
"href": "#{person.url}owa"
}
]
}
JSON
<Link rel="http://purl.org/macgirvin/dfrn/1.0"
href="#{person.profile_url}" />
<Link rel="http://schemas.google.com/g/2010#updates-from"
type="application/atom+xml"
href="#{person.atom_url}" />
<Link rel="http://webfinger.net/rel/profile-page"
type="text/html"
href="#{person.profile_url}" />
<Link rel="http://microformats.org/profile/hcard"
type="text/html"
href="#{person.hcard_url}" />
<Link rel="http://portablecontacts.net/spec/1.0"
href="https://pod.example.tld/poco/trouble" />
<Link rel="http://webfinger.net/rel/avatar"
type="image/jpeg"
href="http://localhost:3000/assets/user/default.png" />
<Link rel="http://joindiaspora.com/seed_location" type="text/html" href="#{person.url}" />
<Link rel="http://joindiaspora.com/guid" type="text/html" href="#{person.guid}" />
<Link rel="diaspora-public-key" type="RSA" href="#{public_key_base64}" />
<Link rel="salmon"
href="#{person.salmon_url}" />
<Link rel="http://salmon-protocol.org/ns/salmon-replies"
href="https://pod.example.tld/salmon/trouble" />
<Link rel="http://salmon-protocol.org/ns/salmon-mention"
href="https://pod.example.tld/salmon/trouble/mention" />
<Link rel="http://ostatus.org/schema/1.0/subscribe"
template="https://pod.example.tld/follow?url={uri}" />
<Link rel="magic-public-key"
href="data:application/magic-public-key,RSA.abcdef1234567890" />
<Property xmlns:mk="http://salmon-protocol.org/ns/magic-key"
type="http://salmon-protocol.org/ns/magic-key"
mk:key_id="1">RSA.abcdef1234567890</Property>
</XRD>
XML
wf = Discovery::WebFinger.from_xml(friendica_xml)
wf = Discovery::WebFinger.from_json(friendica_json)
expect(wf.acct_uri).to eq(acct)
expect(wf.hcard_url).to eq(person.hcard_url)
expect(wf.hcard_url).to eq(friendica_hcard_url)
expect(wf.seed_url).to eq(person.url)
expect(wf.profile_url).to eq(person.profile_url)
expect(wf.atom_url).to eq(person.atom_url)
expect(wf.salmon_url).to eq(person.salmon_url)
expect(wf.subscribe_url).to eq("https://pod.example.tld/follow?url={uri}")
expect(wf.profile_url).to eq(friendica_profile_url)
expect(wf.atom_url).to eq(friendica_atom_url)
expect(wf.salmon_url).to eq(friendica_salmon_url)
expect(wf.subscribe_url).to eq(friendica_subscribe_url)
end
it "reads redmatrix XML (no alias)" do
redmatrix_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
it "reads hubzilla JSON" do
hubzilla_hcard_url = "#{person.url}hcard/#{person.nickname}"
hubzilla_profile_url = "#{person.url}profile/#{person.nickname}"
hubzilla_atom_url = "#{person.url}ofeed/#{person.nickname}"
hubzilla_subscribe_url = "#{person.url}follow?f=&url={uri}"
<Subject>#{person.diaspora_id}</Subject>
hubzilla_json = <<~JSON
{
"subject": "#{acct}",
"aliases": [
"#{person.url}channel/#{person.nickname}",
"#{person.url}~#{person.nickname}",
"#{person.url}@#{person.nickname}"
],
"properties": {
"http://webfinger.net/ns/name": "#{person.full_name}",
"http://xmlns.com/foaf/0.1/name": "#{person.full_name}",
"https://w3id.org/security/v1#publicKeyPem": #{person.serialized_public_key.dump},
"http://purl.org/zot/federation": "zot6,zot,activitypub,diaspora"
},
"links": [
{
"rel": "http://webfinger.net/rel/avatar",
"type": "image/jpeg",
"href": "#{person.url}photo/profile/l/2"
},
{
"rel": "http://microformats.org/profile/hcard",
"type": "text/html",
"href": "#{hubzilla_hcard_url}"
},
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "#{person.url}"
},
{
"rel": "http://webfinger.net/rel/profile-page",
"href": "#{hubzilla_profile_url}"
},
{
"rel": "http://schemas.google.com/g/2010#updates-from",
"type": "application/atom+xml",
"href": "#{hubzilla_atom_url}"
},
{
"rel": "http://webfinger.net/rel/blog",
"href": "#{person.url}channel/#{person.nickname}"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "#{hubzilla_subscribe_url}"
},
{
"rel": "http://purl.org/zot/protocol/6.0",
"type": "application/x-zot+json",
"href": "#{person.url}channel/#{person.nickname}"
},
{
"rel": "http://purl.org/zot/protocol",
"href": "#{person.url}.well-known/zot-info?address=#{person.nickname}@#{person.diaspora_id.split('@')[1]}"
},
{
"rel": "http://purl.org/openwebauth/v1",
"type": "application/x-zot+json",
"href": "#{person.url}owa"
},
{
"rel": "magic-public-key",
"href": "data:application/magic-public-key,RSA.abcdef1234567890"
},
{
"rel": "self",
"type": "application/ld+json; profile=\\\"https://www.w3.org/ns/activitystreams\\\"",
"href": "#{person.url}channel/#{person.nickname}"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "#{person.url}channel/#{person.nickname}"
},
{
"rel": "http://joindiaspora.com/seed_location",
"type": "text/html",
"href": "#{person.url}"
},
{
"rel": "salmon",
"href": "#{person.salmon_url}"
}
]
}
JSON
<Link rel="http://schemas.google.com/g/2010#updates-from"
type="application/atom+xml"
href="#{person.atom_url}" />
<Link rel="http://webfinger.net/rel/profile-page"
type="text/html"
href="#{person.profile_url}" />
<Link rel="http://portablecontacts.net/spec/1.0"
href="https://pod.example.tld/poco/trouble" />
<Link rel="http://webfinger.net/rel/avatar"
type="image/jpeg"
href="http://localhost:3000/assets/user/default.png" />
<Link rel="http://microformats.org/profile/hcard"
type="text/html"
href="#{person.hcard_url}" />
<Link rel="magic-public-key"
href="data:application/magic-public-key,RSA.abcdef1234567890" />
<Link rel="http://joindiaspora.com/seed_location" type="text/html" href="#{person.url}" />
<Link rel="http://joindiaspora.com/guid" type="text/html" href="#{person.guid}" />
<Link rel="diaspora-public-key" type="RSA" href="#{public_key_base64}" />
</XRD>
XML
wf = Discovery::WebFinger.from_xml(redmatrix_xml)
expect(wf.acct_uri).to eq(person.diaspora_id)
expect(wf.hcard_url).to eq(person.hcard_url)
wf = Discovery::WebFinger.from_json(hubzilla_json)
expect(wf.acct_uri).to eq(acct)
expect(wf.hcard_url).to eq(hubzilla_hcard_url)
expect(wf.seed_url).to eq(person.url)
expect(wf.profile_url).to eq(person.profile_url)
expect(wf.atom_url).to eq(person.atom_url)
expect(wf.salmon_url).to be_nil
expect(wf.profile_url).to eq(hubzilla_profile_url)
expect(wf.atom_url).to eq(hubzilla_atom_url)
expect(wf.salmon_url).to eq(person.salmon_url)
expect(wf.subscribe_url).to eq(hubzilla_subscribe_url)
end
it "fails if the document is empty" do
invalid_xml = <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
</XRD>
XML
expect { Discovery::WebFinger.from_xml(invalid_xml) }.to raise_error Discovery::InvalidData
invalid_json = <<~JSON
{}
JSON
expect { Discovery::WebFinger.from_json(invalid_json) }.to raise_error Discovery::InvalidData
end
it "fails if the document is not XML" do
expect { Discovery::WebFinger.from_xml("") }.to raise_error Discovery::InvalidDocument
it "fails if the document is not JSON" do
expect { Discovery::WebFinger.from_json("") }.to raise_error Discovery::InvalidDocument
end
it "does not support XML anymore" do
expect { Discovery::WebFinger.from_xml("") }
.to raise_error "Parsing WebFinger as XML is not supported anymore, use 'from_json' instead."
end
end
end

View file

@ -4,13 +4,6 @@ module DiasporaFederation
describe ReceiveController, type: :routing do
routes { DiasporaFederation::Engine.routes }
it "routes GET host-meta" do
expect(get: ".well-known/host-meta").to route_to(
controller: "diaspora_federation/webfinger",
action: "host_meta"
)
end
it "routes GET webfinger" do
expect(get: "/.well-known/webfinger").to route_to(
controller: "diaspora_federation/webfinger",