diff --git a/app/controllers/webfinger_controller.rb b/app/controllers/webfinger_controller.rb new file mode 100644 index 0000000..5cf4012 --- /dev/null +++ b/app/controllers/webfinger_controller.rb @@ -0,0 +1,57 @@ +class WebfingerController < ApplicationController + before_action :allow_cross_origin_requests, only: [:show] + + layout false + + def show + resource = params[:resource] + + if resource && resource.match(/acct:\w+/) + useraddress = resource.split(":").last + username, org = useraddress.split("@") + username.downcase! + unless User.where(cn: username, ou: org).any? + head 404 and return + end + + render json: webfinger(useraddress).to_json, + content_type: "application/jrd+json" + else + head 422 and return + end + end + + private + + def webfinger(useraddress) + links = []; + + links << remotestorage_link(useraddress) if Setting.remotestorage_enabled + + { "links" => links } + end + + def remotestorage_link(useraddress) + # TODO use when OAuth routes are available + # auth_url = new_rs_oauth_url(useraddress) + auth_url = "https://example.com/rs/oauth" + storage_url = "#{Setting.rs_storage_url}/#{useraddress}" + + { + "rel" => "http://tools.ietf.org/id/draft-dejong-remotestorage", + "href" => storage_url, + "properties" => { + "http://remotestorage.io/spec/version" => "draft-dejong-remotestorage-13", + "http://tools.ietf.org/html/rfc6749#section-4.2" => auth_url, + "http://tools.ietf.org/html/rfc6750#section-2.3" => nil, # access token via a HTTP query parameter + "http://tools.ietf.org/html/rfc7233": "GET", # content range requests + "http://remotestorage.io/spec/web-authoring": nil + } + } + end + + def allow_cross_origin_requests + headers['Access-Control-Allow-Origin'] = '*' + headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS' + end +end diff --git a/config/routes.rb b/config/routes.rb index e729019..e75eda4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,6 +54,8 @@ Rails.application.routes.draw do end end + get ".well-known/webfinger" => "webfinger#show" + authenticate :user, ->(user) { user.is_admin? } do mount Sidekiq::Web => '/sidekiq' end diff --git a/spec/requests/webfinger_spec.rb b/spec/requests/webfinger_spec.rb new file mode 100644 index 0000000..f944a7a --- /dev/null +++ b/spec/requests/webfinger_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe "WebFinger", type: :request do + describe "remoteStorage link relation" do + context "user exists" do + before do + create :user, cn: 'tony', ou: 'kosmos.org' + end + + context "remoteStorage enabled globally" do + it "includes the remoteStorage link for the user" do + get "/.well-known/webfinger?resource=acct%3Atony%40kosmos.org" + expect(response).to have_http_status(:ok) + + res = JSON.parse(response.body) + rs_link = res["links"].find {|l| l["rel"] == "http://tools.ietf.org/id/draft-dejong-remotestorage"} + + expect(rs_link["href"]).to eql("https://storage.kosmos.org/tony@kosmos.org") + + oauth_url = rs_link["properties"]["http://tools.ietf.org/html/rfc6749#section-4.2"] + expect(oauth_url).to eql("https://example.com/rs/oauth") + end + end + + context "remoteStorage not available" do + before do + Setting.remotestorage_enabled = false + end + + it "does not include the remoteStorage link" do + get "/.well-known/webfinger?resource=acct%3Atony%40kosmos.org" + expect(response).to have_http_status(:ok) + + res = JSON.parse(response.body) + rs_link = res["links"].find {|l| l["rel"] == "http://tools.ietf.org/id/draft-dejong-remotestorage"} + + expect(rs_link).to be_nil + end + end + end + + context "user does not exist" do + it "does return a 404 status" do + get "/.well-known/webfinger?resource=acct%3Ajane.doe%40kosmos.org" + expect(response).to have_http_status(:not_found) + end + end + end +end