Compare commits

..

2 commits

Author SHA1 Message Date
Sebastian Jambor
a54c0993c1 sign json ld fetches 2023-12-17 23:06:57 +01:00
Sebastian Jambor
fa829953a9 allow jrd+json in json_ld_controller to support strict webfinger endpoints 2023-08-08 19:51:30 +02:00
5 changed files with 70 additions and 15 deletions

View file

@ -60,7 +60,7 @@ gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.4.1', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15'
gem 'nokogiri', '~> 1.14'
gem 'nsa', '~> 0.2'
gem 'oj', '~> 3.13'
gem 'ox', '~> 2.14'

View file

@ -405,7 +405,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mini_mime (1.1.2)
mini_portile2 (2.8.4)
mini_portile2 (2.8.2)
minitest (5.17.0)
msgpack (1.6.0)
multi_json (1.15.0)
@ -424,8 +424,8 @@ GEM
net-protocol
net-ssh (7.0.1)
nio4r (2.5.9)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
nokogiri (1.14.5)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nsa (0.2.8)
activesupport (>= 4.2, < 7)
@ -496,7 +496,7 @@ GEM
pundit (2.3.0)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.7.1)
racc (1.6.2)
rack (2.2.7)
rack-attack (6.6.1)
rack (>= 1.0, < 3)
@ -822,7 +822,7 @@ DEPENDENCIES
memory_profiler
mime-types (~> 3.4.1)
net-ldap (~> 0.17)
nokogiri (~> 1.15)
nokogiri (~> 1.14)
nsa (~> 0.2)
oj (~> 3.13)
omniauth (~> 1.9)

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require "faraday"
require "uri"
class Api::V1::JsonLdController < Api::BaseController
include ActionController::Live
@ -9,6 +10,40 @@ class Api::V1::JsonLdController < Api::BaseController
render json: { error: e.to_s }, status: 422
end
before_action :require_user!
REQUEST_TARGET = '(request-target)'
def signature(headers)
account = Account.representative
key_id = ActivityPub::TagManager.instance.key_uri_for(account)
algorithm = 'rsa-sha256'
signed_string = headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
signature = Base64.strict_encode64(account.keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
"keyId=\"#{key_id}\",algorithm=\"#{algorithm}\",headers=\"#{headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
end
def signed_headers(url_string)
if url_string.include?(".well-known")
return {'Accept': 'application/jrd+json'}
end
url = URI.parse(url_string)
tmp_headers = {
'Date': Time.now.utc.httpdate,
'Host': url.host,
'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
}
tmp_headers[REQUEST_TARGET] = "get #{url_string.delete_prefix("#{url.scheme}://#{url.host}")}"
additional_headers = {
'Signature': signature(tmp_headers),
'User-Agent': Mastodon::Version.user_agent,
}
tmp_headers.merge(additional_headers).except(REQUEST_TARGET)
end
def show
url = params[:url]
@ -17,13 +52,12 @@ class Api::V1::JsonLdController < Api::BaseController
Thread.new {
begin
conn = Faraday::Connection.new
conn.options.timeout = 5
api_response = conn.get(url, nil, {'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'})
api_response = conn.get(url, nil, signed_headers(url))
max_redirects = 5
while api_response.status == 301 || api_response.status == 302 and max_redirects > 0 do
api_response = conn.get(api_response.headers['Location'], nil, {'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'})
api_response = conn.get(api_response.headers['Location'], nil, signed_headers(api_response.headers['Location']))
max_redirects -= 1
end

View file

@ -1,14 +1,14 @@
- thumbnail = @instance_presenter.thumbnail
- description ||= @instance_presenter.description.presence || strip_tags(t('about.about_mastodon_html'))
- description = 'Learn ActivityPub interactively, by seeing protocol interactions visualized in real time'
%meta{ name: 'description', content: description }/
= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)
= opengraph 'og:site_name', 'ActivityPub Academy - A learning resource for ActivityPub'
= opengraph 'og:url', url_for(only_path: false)
= opengraph 'og:type', 'website'
= opengraph 'og:title', @instance_presenter.title
= opengraph 'og:title', 'ActivityPub Academy'
= opengraph 'og:description', description
= opengraph 'og:image', full_asset_url(thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/preview.png', protocol: :request))
= opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '1200'
= opengraph 'og:image:height', thumbnail ? thumbnail.meta['height'] : '630'
= opengraph 'og:image', full_asset_url(thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/academy-mascot.webp', protocol: :request))
= opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '500'
= opengraph 'og:image:height', thumbnail ? thumbnail.meta['height'] : '573'
= opengraph 'twitter:card', 'summary_large_image'

21
dist/nginx.conf vendored
View file

@ -114,6 +114,27 @@ server {
tcp_nodelay on;
}
location ^~ /api/v1/json_ld {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://backend;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection '';
proxy_cache off;
proxy_buffering off;
chunked_transfer_encoding off;
tcp_nodelay on;
}
location ^~ /api/v1/activity_log {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;