about summary refs log tree commit diff
path: root/app/lib/activitypub/dereferencer.rb
blob: 4d7756d71d880b24dc55d5e006e6730ab17722ee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# frozen_string_literal: true

class ActivityPub::Dereferencer
  include JsonLdHelper

  def initialize(uri, permitted_origin: nil, signature_actor: nil)
    @uri               = uri
    @permitted_origin  = permitted_origin
    @signature_actor = signature_actor
  end

  def object
    @object ||= fetch_object!
  end

  private

  def bear_cap?
    @uri.start_with?('bear:')
  end

  def fetch_object!
    if bear_cap?
      fetch_with_token!
    else
      fetch_with_signature!
    end
  end

  def fetch_with_token!
    perform_request(bear_cap['u'], headers: { 'Authorization' => "Bearer #{bear_cap['t']}" })
  end

  def fetch_with_signature!
    perform_request(@uri)
  end

  def bear_cap
    @bear_cap ||= Addressable::URI.parse(@uri).query_values
  end

  def perform_request(uri, headers: nil)
    return if invalid_origin?(uri)

    req = Request.new(:get, uri)

    req.add_headers('Accept' => 'application/activity+json, application/ld+json')
    req.add_headers(headers) if headers
    req.on_behalf_of(@signature_actor) if @signature_actor

    req.perform do |res|
      if res.code == 200
        json = body_to_json(res.body_with_limit)
        json if json.present? && json['id'] == uri
      else
        raise Mastodon::UnexpectedResponseError, res unless response_successful?(res) || response_error_unsalvageable?(res)
      end
    end
  end

  def invalid_origin?(uri)
    return true if unsupported_uri_scheme?(uri)

    needle   = Addressable::URI.parse(uri).host
    haystack = Addressable::URI.parse(@permitted_origin).host

    !haystack.casecmp(needle).zero?
  end
end