CI / Test (pull_request) Successful in 41s
Implements the optional OAuth 2.0 Authorization Code grant with PKCE (RFC 7636) for remoteStorage, as described in the remoteStorage spec (section 10.1). - Advertise the authorization and token endpoints plus the supported code_challenge method (S256) in WebFinger, and bump the advertised spec version to draft-dejong-remotestorage-27 - Add RsAuthorizationCode: a short-lived (5 min), single-use authorization code stored only as a SHA256 digest - Add RsOauthManager services for issuing and exchanging codes, including S256 verification - Add a cross-origin POST /rs/oauth/token endpoint that exchanges a code (and code_verifier) for an access token, with CORS and no CSRF token - Consent dialog now carries response_type / code_challenge through the form and redirects with the code in the query string for the code flow - Remove the existing-token reuse shortcut so every authorization results in a distinct authorization (and token) Part of #254
130 lines
3.5 KiB
Ruby
130 lines
3.5 KiB
Ruby
class WebfingerController < WellKnownController
|
|
before_action :allow_cross_origin_requests, only: [:show]
|
|
|
|
def show
|
|
resource = params[:resource]
|
|
|
|
if resource && @useraddress = resource.match(/acct:(.+)/)&.[](1)
|
|
@username, @domain = @useraddress.split("@")
|
|
|
|
unless Rails.env.development?
|
|
# Allow different domains (e.g. localhost:3000) in development only
|
|
head 404 and return unless @domain == Setting.primary_domain
|
|
end
|
|
|
|
unless @user = User.where(ou: Setting.primary_domain)
|
|
.find_by(cn: @username.downcase)
|
|
head 404 and return
|
|
end
|
|
|
|
render json: webfinger.to_json,
|
|
content_type: "application/jrd+json"
|
|
else
|
|
head 422 and return
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def webfinger
|
|
jrd = {
|
|
subject: "acct:#{@user.address}",
|
|
aliases: [],
|
|
links: []
|
|
}
|
|
|
|
if @user.avatar.attached?
|
|
jrd[:links] += avatar_link
|
|
end
|
|
|
|
if Setting.mastodon_enabled && @user.service_enabled?(:mastodon)
|
|
# https://docs.joinmastodon.org/spec/webfinger/
|
|
jrd[:aliases] += mastodon_aliases
|
|
jrd[:links] += mastodon_links
|
|
end
|
|
|
|
if Setting.remotestorage_enabled && @user.service_enabled?(:remotestorage)
|
|
# https://datatracker.ietf.org/doc/draft-dejong-remotestorage/
|
|
jrd[:links] << remotestorage_link
|
|
end
|
|
|
|
jrd
|
|
end
|
|
|
|
def avatar_link
|
|
[
|
|
{
|
|
rel: "http://webfinger.net/rel/avatar",
|
|
type: @user.avatar.content_type,
|
|
href: helpers.image_url_for(@user.avatar)
|
|
}
|
|
]
|
|
end
|
|
|
|
def mastodon_aliases
|
|
[
|
|
"#{Setting.mastodon_public_url}/@#{@user.cn}",
|
|
"#{Setting.mastodon_public_url}/users/#{@user.cn}"
|
|
]
|
|
end
|
|
|
|
def mastodon_links
|
|
[
|
|
{
|
|
rel: "http://webfinger.net/rel/profile-page",
|
|
type: "text/html",
|
|
href: "#{Setting.mastodon_public_url}/@#{@user.cn}"
|
|
},
|
|
{
|
|
rel: "self",
|
|
type: "application/activity+json",
|
|
href: "#{Setting.mastodon_public_url}/users/#{@user.cn}"
|
|
},
|
|
{
|
|
rel: "http://ostatus.org/schema/1.0/subscribe",
|
|
template: "#{Setting.mastodon_public_url}/authorize_interaction?uri={uri}"
|
|
}
|
|
]
|
|
end
|
|
|
|
def remotestorage_link
|
|
auth_url =
|
|
if Rails.env.development?
|
|
new_rs_oauth_url(@username)
|
|
else
|
|
new_rs_oauth_url(@username, host: Setting.rs_accounts_domain)
|
|
end
|
|
|
|
storage_url = "#{remotestorage_storage_base_url}/#{@username}"
|
|
|
|
{
|
|
rel: "http://tools.ietf.org/id/draft-dejong-remotestorage",
|
|
href: storage_url,
|
|
properties: {
|
|
"http://remotestorage.io/spec/version" => "draft-dejong-remotestorage-27",
|
|
"http://tools.ietf.org/html/rfc6749#section-4.2" => auth_url,
|
|
"http://tools.ietf.org/html/rfc6749#section-3.1" => auth_url,
|
|
"http://tools.ietf.org/html/rfc6749#section-3.2" => token_endpoint_url,
|
|
"http://tools.ietf.org/html/rfc7636" => "S256",
|
|
"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 token_endpoint_url
|
|
return rs_oauth_token_url if Rails.env.development?
|
|
|
|
rs_oauth_token_url(host: Setting.rs_accounts_domain)
|
|
end
|
|
|
|
def remotestorage_storage_base_url
|
|
return Setting.rs_storage_url unless Rails.env.development?
|
|
|
|
uri = URI.parse(Setting.rs_storage_url)
|
|
uri.host = request.host
|
|
uri.to_s
|
|
end
|
|
end
|