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 module DiasporaFederation
# This controller handles all webfinger-specific requests. # This controller handles all webfinger-specific requests.
class WebfingerController < ApplicationController 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. # Returns the webfinger as RFC 7033 JRD or XRD.
# #
# JSON example: # 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> # GET /.well-known/webfinger?resource=<uri>
def webfinger def webfinger
person_wf = find_person_webfinger(params.require(:resource)) person_wf = find_person_webfinger(params.require(:resource))
@ -80,24 +52,11 @@ module DiasporaFederation
if person_wf.nil? if person_wf.nil?
head :not_found head :not_found
else 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"] = "*" headers["Access-Control-Allow-Origin"] = "*"
render json: JSON.pretty_generate(person_wf.to_json), content_type: "application/jrd+json" render json: JSON.pretty_generate(person_wf.to_json), content_type: "application/jrd+json"
end end
format.any(:xrd, :xml) do
render xml: person_wf.to_xml, content_type: "application/xrd+xml"
end
end
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 end
private private

View file

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

View file

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

View file

@ -24,7 +24,7 @@ module DiasporaFederation
validate_diaspora_id validate_diaspora_id
DiasporaFederation.callbacks.trigger(:save_person_after_webfinger, person) DiasporaFederation.callbacks.trigger(:save_person_after_webfinger, person)
logger.info "successfully webfingered #{diaspora_id}" logger.info "Successfully webfingered #{diaspora_id}"
person person
rescue DiscoveryError rescue DiscoveryError
raise # simply re-raise DiscoveryError raise # simply re-raise DiscoveryError
@ -67,22 +67,11 @@ module DiasporaFederation
"acct:#{diaspora_id}" "acct:#{diaspora_id}"
end 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 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. # 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)) @webfinger ||=
rescue => e # rubocop:disable Style/RescueStandardError WebFinger.from_json(get("https://#{domain}/.well-known/webfinger?resource=#{acct_parameter}",
logger.warn "WebFinger failed, retrying with legacy WebFinger for #{diaspora_id}: #{e.class}: #{e.message}" http_fallback: DiasporaFederation.webfinger_http_fallback))
@webfinger = WebFinger.from_xml(get(legacy_webfinger_url_from_host_meta))
end end
def hcard 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 DiasporaFederation
module Discovery module Discovery
# The WebFinger document used for diaspora* user discovery is based on an # 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}. # {https://datatracker.ietf.org/doc/html/rfc7033 RFC 7033}.
#
# In the meantime an actual RFC draft has been in development, which should
# serve as a base for all future changes of this implementation.
# #
# @example Creating a WebFinger document from a person hash # @example Creating a WebFinger document from a person hash
# wf = WebFinger.new( # wf = WebFinger.new(
@ -17,22 +14,20 @@ module DiasporaFederation
# atom_url: "https://server.example/public/user.atom", # atom_url: "https://server.example/public/user.atom",
# salmon_url: "https://server.example/receive/users/0123456789abcdef" # 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 # @example Creating a WebFinger instance from an JSON document
# wf = WebFinger.from_xml(xml_string) # wf = WebFinger.from_json(json_string)
# ... # ...
# hcard_url = wf.hcard_url # 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 # @see http://www.iana.org/assignments/link-relations/link-relations.xhtml
# official list of IANA link relations # official list of IANA link relations
class WebFinger < Entity class WebFinger < Entity
# @!attribute [r] acct_uri # @!attribute [r] acct_uri
# The Subject element should contain the webfinger address that was asked # The Subject element should contain the WebFinger address that was asked
# for. If it does not, then this webfinger profile MUST be ignored. # for. If it does not, then this WebFinger profile MUST be ignored.
# @return [String] # @return [String]
property :acct_uri, :string property :acct_uri, :string
@ -67,7 +62,7 @@ module DiasporaFederation
property :salmon_url, :string, optional: true property :salmon_url, :string, optional: true
# @!attribute [r] subscribe_url # @!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 property :subscribe_url, :string, optional: true
# +hcard_url+ link relation # +hcard_url+ link relation
@ -106,29 +101,29 @@ module DiasporaFederation
super(data) super(data)
end end
# Creates the XML string from the current WebFinger instance # @!visibility private
# @return [String] XML string # Generating WebFinger to XML is not supported anymore, use {#to_json} instead.
def to_xml def to_xml
to_xrd.to_xml raise "Generating WebFinger to XML is not supported anymore, use 'to_json' instead."
end end
# Creates the JSON string from the current WebFinger instance
# @return [String] JSON string
def to_json(*_args) def to_json(*_args)
to_xrd.to_json to_xrd.to_json
end end
# Creates a WebFinger instance from the given XML string # @!visibility private
# @param [String] webfinger_xml WebFinger XML string # Parsing WebFinger as XML is not supported anymore, use {from_json} instead.
# @return [WebFinger] WebFinger instance def self.from_xml(_webfinger_xml)
# @raise [InvalidData] if the given XML string is invalid or incomplete raise "Parsing WebFinger as XML is not supported anymore, use 'from_json' instead."
def self.from_xml(webfinger_xml)
from_hash(parse_xml_and_validate(webfinger_xml))
end end
# Creates a WebFinger instance from the given JSON string # Creates a WebFinger instance from the given JSON string
# @param [String] webfinger_json WebFinger JSON string # @param [String] webfinger_json WebFinger JSON string
# @return [WebFinger] WebFinger instance # @return [WebFinger] WebFinger instance
def self.from_json(webfinger_json) def self.from_json(webfinger_json)
from_hash(XrdDocument.json_data(webfinger_json)) from_hash(parse_json_and_validate(webfinger_json))
end end
# Creates a WebFinger instance from the given data # Creates a WebFinger instance from the given data
@ -157,15 +152,15 @@ module DiasporaFederation
private 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. # the data Hash.
# @param [String] webfinger_xml WebFinger XML string # @param [String] webfinger_json WebFinger JSON string
# @return [Hash] data XML data # @return [Hash] data JSON data
# @raise [InvalidData] if the given XML string is invalid or incomplete # @raise [InvalidData] if the given JSON string is invalid or incomplete
private_class_method def self.parse_xml_and_validate(webfinger_xml) private_class_method def self.parse_json_and_validate(webfinger_json)
XrdDocument.xml_data(webfinger_xml).tap do |data| XrdDocument.json_data(webfinger_json).tap do |data|
valid = data.key?(:subject) && data.key?(:links) 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
end end

View file

@ -5,12 +5,8 @@ module DiasporaFederation
# This class implements basic handling of XRD documents as far as it is # This class implements basic handling of XRD documents as far as it is
# necessary in the context of the protocols used with diaspora* federation. # necessary in the context of the protocols used with diaspora* federation.
# #
# @note {http://tools.ietf.org/html/rfc6415 RFC 6415} recommends that servers # It also implements handling of the JRD format, see
# should also offer the JRD format in addition to the XRD representation. # {https://datatracker.ietf.org/doc/html/rfc6415#appendix-A RFC 6415, Appendix A}
# 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. # for a description of the JSON format.
# #
# @example Creating a XrdDocument # @example Creating a XrdDocument
@ -210,7 +206,7 @@ module DiasporaFederation
# symbolize link keys from JSON hash, but only convert known keys # symbolize link keys from JSON hash, but only convert known keys
private_class_method def self.symbolize_keys_for_links(links) private_class_method def self.symbolize_keys_for_links(links)
links.map do |link| links&.map do |link|
{}.tap do |hash| {}.tap do |hash|
LINK_ATTRS.each do |attr| LINK_ATTRS.each do |attr|
hash[attr] = link[attr.to_s] if link.key?(attr.to_s) 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 describe WebfingerController, type: :controller do
routes { DiasporaFederation::Engine.routes } 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 describe "GET #webfinger" do
it "uses the JRD format as default" do it "uses the JRD format as default" do
get :webfinger, params: {resource: alice.diaspora_id} get :webfinger, params: {resource: alice.diaspora_id}
@ -44,7 +11,6 @@ module DiasporaFederation
expect(response.header["Content-Type"]).to include "application/jrd+json" expect(response.header["Content-Type"]).to include "application/jrd+json"
end end
context "json", exceptions: :catch do
it "succeeds when the person exists" do it "succeeds when the person exists" do
get :webfinger, format: :json, params: {resource: alice.diaspora_id} get :webfinger, format: :json, params: {resource: alice.diaspora_id}
expect(response).to be_successful expect(response).to be_successful
@ -87,39 +53,5 @@ module DiasporaFederation
get :webfinger, format: :json, params: {resource: "acct:alice@localhost:3000"} get :webfinger, format: :json, params: {resource: "acct:alice@localhost:3000"}
end end
end 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: :xml, params: {resource: "acct:#{alice.diaspora_id}"}
expect(response).to be_successful
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/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 "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 "calls the fetch_person_for_webfinger callback" do
expect_callback(:fetch_person_for_webfinger, "alice@localhost:3000").and_call_original
get :webfinger, format: :xml, params: {resource: "acct:alice@localhost:3000"}
end
end
end
end end
end end

View file

@ -2,7 +2,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 } subject(:discovery) { Discovery::Discovery.new(account) }
let(:webfinger_data) { let(:webfinger_data) {
{ {
acct_uri: "acct:#{alice.diaspora_id}", acct_uri: "acct:#{alice.diaspora_id}",
@ -17,9 +18,6 @@ module DiasporaFederation
public_key: alice.serialized_public_key public_key: alice.serialized_public_key
} }
} }
let(:webfinger_xrd) {
DiasporaFederation::Discovery::WebFinger.new(webfinger_data).to_xml
}
let(:webfinger_jrd) { let(:webfinger_jrd) {
JSON.pretty_generate(DiasporaFederation::Discovery::WebFinger.new(webfinger_data).to_json) JSON.pretty_generate(DiasporaFederation::Discovery::WebFinger.new(webfinger_data).to_json)
} }
@ -40,7 +38,6 @@ 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
@ -62,7 +59,7 @@ module DiasporaFederation
.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 = subject.fetch_and_save person = discovery.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)
@ -93,7 +90,7 @@ module DiasporaFederation
callback_person = person callback_person = person
end end
expect(subject.fetch_and_save).to be(callback_person) expect(discovery.fetch_and_save).to be(callback_person)
end end
it "fails if the diaspora* ID does not match" do 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}") stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: modified_webfinger) .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 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}") 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/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 end
context "http fallback" do context "with http fallback" do
context "http fallback disabled (default)" do context "when http fallback disabled (default)" do
it "falls back to legacy WebFinger if https fails with 404" 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_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
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}") 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, "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)) expect { discovery.fetch_and_save }.to raise_error Discovery::DiscoveryError
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end end
end end
context "http fallback enabled" do context "when http fallback enabled" do
before :all do before do
DiasporaFederation.webfinger_http_fallback = true DiasporaFederation.webfinger_http_fallback = true
end end
after :all do after do
DiasporaFederation.webfinger_http_fallback = false DiasporaFederation.webfinger_http_fallback = false
end end
@ -175,7 +137,7 @@ module DiasporaFederation
.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 = subject.fetch_and_save person = discovery.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)
@ -190,7 +152,7 @@ module DiasporaFederation
.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 = subject.fetch_and_save person = discovery.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)
@ -198,118 +160,33 @@ module DiasporaFederation
end end
end end
context "legacy WebFinger" do context "with error handling" 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
it "re-raises DiscoveryError" 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!") .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 end
it "re-raises InvalidDocument" do 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!") .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 end
it "re-raises InvalidData" do 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!") .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 end
it "raises a DiscoveryError when an unhandled error occurs" do it "raises a DiscoveryError when an unhandled error occurs" do
expect(subject).to receive(:validate_diaspora_id) allow(discovery).to receive(:validate_diaspora_id).and_raise("OMG! EVERYTHING IS BROKEN!")
.and_raise("OMG! EVERYTHING IS BROKEN!")
expect { expect {
subject.fetch_and_save discovery.fetch_and_save
}.to raise_error Discovery::DiscoveryError, }.to raise_error Discovery::DiscoveryError,
"Failed discovery for #{account}: RuntimeError: OMG! EVERYTHING IS BROKEN!" "Failed discovery for #{account}: RuntimeError: OMG! EVERYTHING IS BROKEN!"
end 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 } let(:json) { <<~JSON }
{ {
"subject": "#{acct}", "subject": "#{acct}",
@ -74,7 +51,7 @@ module DiasporaFederation
}, },
{ {
"rel": "http://ostatus.org/schema/1.0/subscribe", "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" 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(:minimal_data) { {acct_uri: acct, hcard_url: person.hcard_url, seed_url: person.url} }
let(:additional_data) { let(:additional_data) {
{ {
@ -120,39 +97,6 @@ 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
end
context "json" do
it "creates a nice JSON document" do it "creates a nice JSON document" do
wf = Discovery::WebFinger.new(data, aliases: [person.alias_url]) wf = Discovery::WebFinger.new(data, aliases: [person.alias_url])
expect(JSON.pretty_generate(wf.to_json)).to eq(json.strip) expect(JSON.pretty_generate(wf.to_json)).to eq(json.strip)
@ -205,28 +149,14 @@ module DiasporaFederation
wf = Discovery::WebFinger.new(minimal_data, additional_data) wf = Discovery::WebFinger.new(minimal_data, additional_data)
expect(JSON.pretty_generate(wf.to_json)).to eq(json_with_additional_data.strip) expect(JSON.pretty_generate(wf.to_json)).to eq(json_with_additional_data.strip)
end 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
end end
context "parsing" do context "when 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
it "reads its own json output" do it "reads its own json output" do
wf = Discovery::WebFinger.from_json(json) wf = Discovery::WebFinger.from_json(json)
expect(wf.acct_uri).to eq(acct) expect(wf.acct_uri).to eq(acct)
@ -246,119 +176,219 @@ module DiasporaFederation
end end
it "is frozen after parsing" do it "is frozen after parsing" do
wf = Discovery::WebFinger.from_xml(xml) wf = Discovery::WebFinger.from_json(json)
expect(wf).to be_frozen expect(wf).to be_frozen
end end
it "reads friendica XML (two aliases, first with acct)" do it "reads friendica JSON" do
friendica_xml = <<~XML friendica_hcard_url = "#{person.url}hcard/#{person.nickname}"
<?xml version="1.0" encoding="UTF-8"?> friendica_profile_url = "#{person.url}profile/#{person.nickname}"
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> 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> friendica_json = <<~JSON
<Alias>#{acct}</Alias> {
<Alias>#{person.alias_url}</Alias> "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" wf = Discovery::WebFinger.from_json(friendica_json)
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)
expect(wf.acct_uri).to eq(acct) 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.seed_url).to eq(person.url)
expect(wf.profile_url).to eq(person.profile_url) expect(wf.profile_url).to eq(friendica_profile_url)
expect(wf.atom_url).to eq(person.atom_url) expect(wf.atom_url).to eq(friendica_atom_url)
expect(wf.salmon_url).to eq(person.salmon_url) expect(wf.salmon_url).to eq(friendica_salmon_url)
expect(wf.subscribe_url).to eq("https://pod.example.tld/follow?url={uri}") expect(wf.subscribe_url).to eq(friendica_subscribe_url)
end end
it "reads redmatrix XML (no alias)" do it "reads hubzilla JSON" do
redmatrix_xml = <<~XML hubzilla_hcard_url = "#{person.url}hcard/#{person.nickname}"
<?xml version="1.0" encoding="UTF-8"?> hubzilla_profile_url = "#{person.url}profile/#{person.nickname}"
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> 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" wf = Discovery::WebFinger.from_json(hubzilla_json)
type="application/atom+xml" expect(wf.acct_uri).to eq(acct)
href="#{person.atom_url}" /> expect(wf.hcard_url).to eq(hubzilla_hcard_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)
expect(wf.seed_url).to eq(person.url) expect(wf.seed_url).to eq(person.url)
expect(wf.profile_url).to eq(person.profile_url) expect(wf.profile_url).to eq(hubzilla_profile_url)
expect(wf.atom_url).to eq(person.atom_url) expect(wf.atom_url).to eq(hubzilla_atom_url)
expect(wf.salmon_url).to be_nil expect(wf.salmon_url).to eq(person.salmon_url)
expect(wf.subscribe_url).to eq(hubzilla_subscribe_url)
end end
it "fails if the document is empty" do it "fails if the document is empty" do
invalid_xml = <<~XML invalid_json = <<~JSON
<?xml version="1.0" encoding="UTF-8"?> {}
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> JSON
</XRD> expect { Discovery::WebFinger.from_json(invalid_json) }.to raise_error Discovery::InvalidData
XML
expect { Discovery::WebFinger.from_xml(invalid_xml) }.to raise_error Discovery::InvalidData
end end
it "fails if the document is not XML" do it "fails if the document is not JSON" do
expect { Discovery::WebFinger.from_xml("") }.to raise_error Discovery::InvalidDocument 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 end
end end

View file

@ -4,13 +4,6 @@ module DiasporaFederation
describe ReceiveController, type: :routing do describe ReceiveController, type: :routing do
routes { DiasporaFederation::Engine.routes } 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 it "routes GET webfinger" do
expect(get: "/.well-known/webfinger").to route_to( expect(get: "/.well-known/webfinger").to route_to(
controller: "diaspora_federation/webfinger", controller: "diaspora_federation/webfinger",