refactor WebFinger to use the PropertiesDSL

This commit is contained in:
Benjamin Neff 2015-07-06 02:27:11 +02:00
parent e955ef8966
commit 2c50d34370
7 changed files with 110 additions and 104 deletions

View file

@ -33,12 +33,12 @@ module DiasporaFederation
# </XRD>
# GET /webfinger?q=<uri>
def legacy_webfinger
person = find_person(params[:q]) if params[:q]
person_wf = find_person_webfinger(params[:q]) if params[:q]
return render nothing: true, status: 404 if person.nil?
return render nothing: true, status: 404 if person_wf.nil?
logger.info "webfinger profile request for: #{person.diaspora_handle}"
render body: WebFinger::WebFinger.from_person(person).to_xml, content_type: "application/xrd+xml"
logger.info "webfinger profile request for: #{person_wf.acct_uri}"
render body: person_wf.to_xml, content_type: "application/xrd+xml"
end
private
@ -49,8 +49,8 @@ module DiasporaFederation
@host_meta_xml ||= WebFinger::HostMeta.from_base_url(DiasporaFederation.server_uri.to_s).to_xml
end
def find_person(query)
DiasporaFederation.person_class.find_local_by_diaspora_handle(query.strip.downcase.gsub("acct:", ""))
def find_person_webfinger(query)
DiasporaFederation.callbacks.trigger(:person_webfinger_fetch, query.strip.downcase.gsub("acct:", ""))
end
end
end

View file

@ -8,19 +8,19 @@ module DiasporaFederation
# 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 object
# xml_string = WebFinger.from_person(person).to_xml
#
# The person object should have the following attributes (with examples)
# diaspora_handle: "user@server.example"
# alias_url: "https://server.example/people/0123456789abcdef"
# hcard_url: "https://server.example/hcard/users/0123456789abcdef"
# seed_url: "https://server.example/"
# profile_url: "https://server.example/u/user"
# atom_url: "https://server.example/public/user.atom"
# salmon_url: "https://server.example/receive/users/0123456789abcdef"
# guid: "0123456789abcdef"
# serialized_public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----"
# @example Creating a WebFinger document from a person hash
# wf = WebFinger.new(
# acct_uri: "acct:user@server.example",
# alias_url: "https://server.example/people/0123456789abcdef",
# hcard_url: "https://server.example/hcard/users/user",
# seed_url: "https://server.example/",
# profile_url: "https://server.example/u/user",
# atom_url: "https://server.example/public/user.atom",
# salmon_url: "https://server.example/receive/users/0123456789abcdef",
# guid: "0123456789abcdef",
# public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----"
# )
# xml_string = wf.to_xml
#
# @example Creating a WebFinger instance from an xml document
# wf = WebFinger.from_xml(xml_string)
@ -33,62 +33,72 @@ module DiasporaFederation
# @see http://code.google.com/p/webfinger/wiki/CommonLinkRelations
# @see http://www.iana.org/assignments/link-relations/link-relations.xhtml
# official list of IANA link relations
class WebFinger
private_class_method :new
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.
# @return [String]
property :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.
# @return [String]
attr_reader :acct_uri
# @!attribute [r] alias_url
# @return [String] link to the users profile
property :alias_url
# @return [String] link to the users profile
attr_reader :alias_url, :profile_url
# @!attribute [r] hcard_url
# @return [String] link to the +hCard+
property :hcard_url
# @return [String] link to the +hCard+
attr_reader :hcard_url
# @!attribute [r] seed_url
# @return [String] link to the pod
property :seed_url
# @return [String] link to the pod
attr_reader :seed_url
# @!attribute [r] profile_url
# @return [String] link to the users profile
property :profile_url
# This atom feed is an Activity Stream of the user's public posts. Diaspora
# pods SHOULD publish an Activity Stream of public posts, but there is
# currently no requirement to be able to read Activity Streams.
# @see http://activitystrea.ms/ Activity Streams specification
# @!attribute [r] atom_url
# This atom feed is an Activity Stream of the user's public posts. Diaspora
# pods SHOULD publish an Activity Stream of public posts, but there is
# currently no requirement to be able to read Activity Streams.
# @see http://activitystrea.ms/ Activity Streams specification
#
# Note that this feed MAY also be made available through the PubSubHubbub
# mechanism by supplying a <link rel="hub"> in the atom feed itself.
# @return [String] atom feed url
attr_reader :atom_url
# Note that this feed MAY also be made available through the PubSubHubbub
# mechanism by supplying a <link rel="hub"> in the atom feed itself.
# @return [String] atom feed url
property :atom_url
# @return [String] salmon endpoint url
# @see http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-salmon-00.html#SMLR
# Panzer draft for Salmon, paragraph 3.3
attr_reader :salmon_url
# @!attribute [r] salmon_url
# @return [String] salmon endpoint url
# @see http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-salmon-00.html#SMLR
# Panzer draft for Salmon, paragraph 3.3
property :salmon_url
# @deprecated Either convert these to +Property+ elements or move to the
# +hCard+, which actually has fields for an +UID+ defined in the +vCard+
# specification (will affect older Diaspora* installations).
# @!attribute [r] guid
# @deprecated Either convert these to +Property+ elements or move to the
# +hCard+, which actually has fields for an +UID+ defined in the +vCard+
# specification (will affect older Diaspora* installations).
#
# @see HCard#guid
# @see HCard#guid
#
# This is just the guid. When a user creates an account on a pod, the pod
# MUST assign them a guid - a random hexadecimal string of at least 8
# hexadecimal digits.
# @return [String] guid
attr_reader :guid
# This is just the guid. When a user creates an account on a pod, the pod
# MUST assign them a guid - a random hexadecimal string of at least 8
# hexadecimal digits.
# @return [String] guid
property :guid
# @deprecated Either convert these to +Property+ elements or move to the
# +hCard+, which actually has fields for an +KEY+ defined in the +vCard+
# specification (will affect older Diaspora* installations).
# @!attribute [r] public_key
# @deprecated Either convert these to +Property+ elements or move to the
# +hCard+, which actually has fields for an +KEY+ defined in the +vCard+
# specification (will affect older Diaspora* installations).
#
# @see HCard#pubkey
# @see HCard#pubkey
#
# When a user is created on the pod, the pod MUST generate a pgp keypair
# for them. This key is used for signing messages. The format is a
# DER-encoded PKCS#1 key beginning with the text
# "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
# @return [String] public key
attr_reader :public_key
# When a user is created on the pod, the pod MUST generate a pgp keypair
# for them. This key is used for signing messages. The format is a
# DER-encoded PKCS#1 key beginning with the text
# "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
# @return [String] public key
property :public_key
# +hcard_url+ link relation
REL_HCARD = "http://microformats.org/profile/hcard"
@ -130,31 +140,6 @@ module DiasporaFederation
doc.to_xml
end
# Create a WebFinger instance from the given person.
# @param [Person] person the person object
# @return [WebFinger] WebFinger instance
# @raise [ArgumentError] if the given person is nil
def self.from_person(person)
raise ArgumentError, "person is nil" if person.nil?
wf = allocate
wf.instance_eval {
@acct_uri = "acct:#{person.diaspora_handle}"
@alias_url = person.alias_url
@hcard_url = person.hcard_url
@seed_url = person.seed_url
@profile_url = person.profile_url
@atom_url = person.atom_url
@salmon_url = person.salmon_url
# TODO: remove me! #########
@guid = person.guid
@public_key = person.serialized_public_key
#############################
}
wf
end
# Create a WebFinger instance from the given XML string.
# @param [String] webfinger_xml WebFinger XML string
# @return [WebFinger] WebFinger instance

View file

@ -58,8 +58,10 @@ module DiasporaFederation
expect(response).to be_not_found
end
it "calls WebFinger::WebFinger.from_person" do
expect(WebFinger::WebFinger).to receive(:from_person).with(alice).and_call_original
it "calls the person_webfinger_fetch callback" do
expect(DiasporaFederation.callbacks).to receive(:trigger)
.with(:person_webfinger_fetch, "alice@localhost:3000")
.and_call_original
get :legacy_webfinger, "q" => "acct:alice@localhost:3000"
end
end

View file

@ -11,7 +11,7 @@ module DiasporaFederation
<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.seed_url}"/>
<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="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}"/>
@ -22,17 +22,27 @@ XML
}
it "must not create blank instances" do
expect { WebFinger::WebFinger.new }.to raise_error NameError
expect { WebFinger::WebFinger.new({}) }.to raise_error ArgumentError
end
context "generation" do
it "creates a nice XML document" do
wf = WebFinger::WebFinger.from_person(person)
wf = WebFinger::WebFinger.new(
acct_uri: "acct:#{person.diaspora_handle}",
alias_url: person.alias_url,
hcard_url: person.hcard_url,
seed_url: person.url,
profile_url: person.profile_url,
atom_url: person.atom_url,
salmon_url: person.salmon_url,
guid: person.guid,
public_key: person.serialized_public_key
)
expect(wf.to_xml).to eq(xml)
end
it "fails if nil was given" do
expect { WebFinger::WebFinger.from_person(nil) }.to raise_error ArgumentError
expect { WebFinger::WebFinger.new(nil) }.to raise_error ArgumentError, "expected a Hash"
end
end
@ -42,7 +52,7 @@ XML
expect(wf.acct_uri).to eq(acct)
expect(wf.alias_url).to eq(person.alias_url)
expect(wf.hcard_url).to eq(person.hcard_url)
expect(wf.seed_url).to eq(person.seed_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)
@ -58,7 +68,7 @@ XML
<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.seed_url}"/>
<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="http://webfinger.net/rel/profile-page" type="text/html" href="#{person.profile_url}"/>
@ -73,7 +83,7 @@ XML
expect(wf.acct_uri).to eq(acct)
expect(wf.alias_url).to eq(person.alias_url)
expect(wf.hcard_url).to eq(person.hcard_url)
expect(wf.seed_url).to eq(person.seed_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)

View file

@ -28,7 +28,7 @@ require "entities"
# some helper methods
def alice
@alice ||= Person.find_local_by_diaspora_handle("alice@localhost:3000")
@alice ||= Person.find_by(diaspora_handle: "alice@localhost:3000")
end
# Force fixture rebuild

View file

@ -7,8 +7,6 @@ class Person < ActiveRecord::Base
def atom_url; "#{url}public/#{diaspora_handle.split('@')[0]}.atom" end
def salmon_url; "#{url}receive/users/#{guid}" end
alias_attribute :seed_url, :url
def nickname; diaspora_handle.split("@")[0] end
def photo_large_url; "#{url}assets/user/default.png" end
def photo_medium_url; "#{url}assets/user/default.png" end
@ -19,11 +17,6 @@ class Person < ActiveRecord::Base
def first_name; "Dummy" end
def last_name; "User" end
def self.find_local_by_diaspora_handle(identifier)
# no remote? and closed_account? check ... this class is only for testing
find_by_diaspora_handle(identifier)
end
def self.find_local_by_guid(guid)
# no remote? and closed_account? check ... this class is only for testing
find_by_guid(guid)

View file

@ -1,3 +1,5 @@
require "diaspora_federation/web_finger"
# configure the federation engine
DiasporaFederation.configure do |config|
# the pod url
@ -5,6 +7,20 @@ DiasporaFederation.configure do |config|
config.define_callbacks do
on :person_webfinger_fetch do |handle|
person = Person.find_by(diaspora_handle: handle)
if person
DiasporaFederation::WebFinger::WebFinger.new(
acct_uri: "acct:#{person.diaspora_handle}",
alias_url: person.alias_url,
hcard_url: person.hcard_url,
seed_url: person.url,
profile_url: person.profile_url,
atom_url: person.atom_url,
salmon_url: person.salmon_url,
guid: person.guid,
public_key: person.serialized_public_key
)
end
end
on :person_hcard_fetch do |guid|