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
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# frozen_string_literal: true
require 'English'
helpers do
def curl(ext, url)
p url
response = `/run/current-system/sw/bin/curl --fail-with-body -sSL #{ext} #{url}`
$CHILD_STATUS.success? ? response : nil
end
# def fetch(url, accept = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"')
def fetch(url, accept = 'application/activity+json')
response = curl("-H 'Accept: #{accept}'", url)
response ? JSON.parse(response) : nil
end
# https://github.com/mastodon/mastodon/blob/main/app/lib/request.rb
# , url
def send_signed(object)
keypair = OpenSSL::PKey::RSA.new(File.read('private.pem'))
date = Time.now.utc.httpdate
body = object.to_json
sha256 = OpenSSL::Digest.new('SHA256')
digest = "SHA-256=#{sha256.base64digest(body)}"
recipients = [object['to'], object['cc'], object['bto'], object['bcc'], object['audience']].flatten.compact.uniq
recipients.each do |url|
next if url == 'https://www.w3.org/ns/activitystreams#Public'
host = URI.parse(url).host
inbox = fetch(url)['inbox']
if inbox
request_uri = URI(inbox).request_uri
signed_string = "(request-target): post #{request_uri}\nhost: #{host}\ndate: #{date}\ndigest: #{digest}\ncontent-type: application/activity+json"
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
signed_header = "keyId=\"#{ACTOR}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"#{signature}\""
curl(
"-X POST -H 'Content-Type: application/activity+json' -H 'Host: #{host}' -H 'Date: #{date}' -H 'Digest: #{digest}' -H 'Signature: #{signed_header}' -d '#{body}'", inbox
)
else
p "No inbox for #{url}"
end
end
end
def people
File.read('cache/people.tsv').split("\n").collect { |l| l.chomp.split("\t") }
end
def mention(actor)
person = people.select { |p| p[1] == actor }
if person.empty?
a = fetch(actor)
return nil unless a
mention = "#{a['preferredUsername']}@#{URI(actor).host}"
File.open('cache/people.tsv', 'a') { |f| f.puts "#{mention}\t#{actor}" }
mention
else
person[0][0]
end
end
def actor(mention)
mention = mention.sub(/^@/, '').chomp
actors = people.select { |p| p[0] == mention }
if actors.empty?
_, server = mention.split('@')
a = fetch("https://#{server}/.well-known/webfinger?resource=acct:#{mention}", 'application/jrd+json')
return nil unless a
actor = a['links'].select do |l|
l['rel'] == 'self'
end[0]['href']
File.open('cache/people.tsv', 'a') { |f| f.puts "#{mention}\t#{actor}" }
actor
else
actors[0][1]
end
end
end
|