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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
helpers do
def items
nr = 0
@items = Dir[File.join(@dir, '*.json')].sort.collect do |file|
item = JSON.parse(File.read(file))
mention = mention(item['attributedTo'])
following_path = File.join('public', 'following', mention + '.json')
File.exists?(following_path) ? follow = 'unfollow' : follow = 'follow'
nr += 1
{ :id => item['id'],
:nr => nr,
:parent => item['inReplyTo'],
:file => file,
:actor_url => item['attributedTo'],
:mention => mention,
:follow => follow,
:content => item['content'],
:attachment => item['attachment'],
:indent => 2,
:replies => []
}
end.compact
@items.last[:nr] = @items.last[:nr] - 2 unless @items.empty?
end
def threads
items
@threads = []
@items.each do |i|
if i[:parent].nil? or @items.select{|it| it[:id] == i[:parent] }.empty?
@threads << i
else
@items.select{|it| it[:id] == i[:parent] }.each do |it|
i[:indent] = it[:indent] + 2
it[:replies] << i
end
end
end
end
def html item
@item = item
erb :item
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?
mention = "#{fetch(actor)["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?
user, server = mention.split("@")
actor = fetch("https://#{server}/.well-known/webfinger?resource=acct:#{mention}",
"application/jrd+json")["links"].select { |l|
l["rel"] == "self"
}[0]["href"]
File.open('cache/people.tsv','a'){|f| f.puts "#{mention}\t#{actor}"}
actor
else
actors[0][1]
end
end
def fetch url, accept = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
p url
response = `/run/current-system/sw/bin/curl --fail-with-body -sSL -H 'Accept: #{accept}' #{url}`
halt 400 unless $?.success?
JSON.parse(response)
end
# https://github.com/mastodon/mastodon/blob/main/app/lib/request.rb
def send_signed object, url
keypair = OpenSSL::PKey::RSA.new(File.read('private.pem'))
date = Time.now.utc.httpdate
sha256 = OpenSSL::Digest::SHA256.new
body = object.to_json
digest = "SHA-256=" + sha256.base64digest(body)
host = URI.parse(url).host
inbox = fetch(url)["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 + '"'
p url
#puts `/run/current-system/sw/bin/curl --fail-with-body -sSL -X POST -H 'Content-Type: application/activity+json' -H 'Host: #{host}' -H 'Date: #{date}' -H 'Digest: #{digest}' -H 'Signature: #{signed_header}' -d '#{body}' #{inbox}`
puts `/run/current-system/sw/bin/curl -iL -X POST -H 'Content-Type: application/activity+json' -H 'Host: #{host}' -H 'Date: #{date}' -H 'Digest: #{digest}' -H 'Signature: #{signed_header}' -d '#{body}' #{inbox}`
end
end
|