From 12cd5b0090afe4eaf50fe7f7c9b1e60305a829bd Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Sat, 13 May 2017 20:22:29 +0200 Subject: [PATCH] Add route for RFC-7033 webfinger --- .../webfinger_controller.rb | 75 ++++++++++++++++ config/initializers/mime_types.rb | 3 + config/routes.rb | 1 + .../webfinger_controller_spec.rb | 85 +++++++++++++++++++ spec/routing/webfinger_routing_spec.rb | 7 ++ 5 files changed, 171 insertions(+) create mode 100644 config/initializers/mime_types.rb diff --git a/app/controllers/diaspora_federation/webfinger_controller.rb b/app/controllers/diaspora_federation/webfinger_controller.rb index 0e755cd..0521ed9 100644 --- a/app/controllers/diaspora_federation/webfinger_controller.rb +++ b/app/controllers/diaspora_federation/webfinger_controller.rb @@ -16,6 +16,81 @@ module DiasporaFederation render xml: WebfingerController.host_meta_xml, content_type: "application/xrd+xml" end + # Returns the webfinger as RFC 7033 JRD or XRD. + # + # JSON example: + # { + # "subject": "acct:alice@localhost:3000", + # "aliases": [ + # "http://localhost:3000/people/c8e87290f6a20132963908fbffceb188" + # ], + # "links": [ + # { + # "rel": "http://microformats.org/profile/hcard", + # "type": "text/html", + # "href": "http://localhost:3000/hcard/users/c8e87290f6a20132963908fbffceb188" + # }, + # { + # "rel": "http://joindiaspora.com/seed_location", + # "type": "text/html", + # "href": "http://localhost:3000/" + # }, + # { + # "rel": "http://webfinger.net/rel/profile-page", + # "type": "text/html", + # "href": "http://localhost:3000/u/alice" + # }, + # { + # "rel": "http://schemas.google.com/g/2010#updates-from", + # "type": "application/atom+xml", + # "href": "http://localhost:3000/public/alice.atom" + # }, + # { + # "rel": "salmon", + # "href": "http://localhost:3000/receive/users/c8e87290f6a20132963908fbffceb188" + # }, + # { + # "rel": "http://ostatus.org/schema/1.0/subscribe", + # "template": "http://localhost:3000/people?q={uri}" + # } + # ] + # } + # + # XML example: + # + # + # acct:alice@localhost:3000 + # http://localhost:3000/people/c8e87290f6a20132963908fbffceb188 + # + # + # + # + # + # + # + # GET /.well-known/webfinger?resource= + def webfinger + person_wf = find_person_webfinger(params.require(:resource)) + + if person_wf.nil? + head :not_found + else + 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 + end + end + # @deprecated This is the pre RFC 7033 webfinger. # # example: diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..10cadb2 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,3 @@ +# mime types for webfinger +Mime::Type.register "application/jrd+json", :jrd +Mime::Type.register "application/xrd+xml", :xrd diff --git a/config/routes.rb b/config/routes.rb index cffd505..d6d0829 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,6 +10,7 @@ DiasporaFederation::Engine.routes.draw do controller :webfinger do get ".well-known/host-meta" => :host_meta, :as => "host_meta" + get ".well-known/webfinger" => :webfinger, :as => "webfinger" get "webfinger" => :legacy_webfinger, :as => "legacy_webfinger" end diff --git a/spec/controllers/diaspora_federation/webfinger_controller_spec.rb b/spec/controllers/diaspora_federation/webfinger_controller_spec.rb index e26ceeb..d740656 100644 --- a/spec/controllers/diaspora_federation/webfinger_controller_spec.rb +++ b/spec/controllers/diaspora_federation/webfinger_controller_spec.rb @@ -35,6 +35,91 @@ module DiasporaFederation end end + describe "GET #webfinger", rails: 5 do + it "uses the JRD format as default" do + get :webfinger, params: {resource: alice.diaspora_id} + expect(response).to be_success + 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_success + 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_success + 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 + end + + context "xml" do + it "succeeds when the person exists" do + get :webfinger, format: :json, params: {resource: alice.diaspora_id} + expect(response).to be_success + 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_success + end + + it "contains the diaspora* ID" do + get :webfinger, format: :xml, params: {resource: "acct:#{alice.diaspora_id}"} + expect(response.body).to include "acct:alice@localhost:3000" + 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 + describe "GET #legacy_webfinger", rails: 5 do it "succeeds when the person exists" do get :legacy_webfinger, params: {q: alice.diaspora_id} diff --git a/spec/routing/webfinger_routing_spec.rb b/spec/routing/webfinger_routing_spec.rb index be2f48c..ccb48d9 100644 --- a/spec/routing/webfinger_routing_spec.rb +++ b/spec/routing/webfinger_routing_spec.rb @@ -9,6 +9,13 @@ module DiasporaFederation ) end + it "routes GET webfinger" do + expect(get: "/.well-known/webfinger").to route_to( + controller: "diaspora_federation/webfinger", + action: "webfinger" + ) + end + it "routes GET legacy webfinger" do expect(get: "/webfinger").to route_to( controller: "diaspora_federation/webfinger",