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
107
108
|
# frozen_string_literal: true
# client-server
['/inbox/threads', '/outbox/threads'].each do |path|
get path do
protected!
box = path.sub('/', '').sub('/threads', '')
collection = Dir[File.join(box, 'object', '*', '*.json')].collect { |f| JSON.parse(File.read(f)) }
threads = []
collection.collect! do |object|
object.is_a?(String) && object.match(/^http/) ? fetch(object) : object
end
collection.compact!
collection.each do |object|
object['mention'] = mention object['attributedTo']
if object['type'] == 'Audio'
audio_url = object['url'].select { |url| url['mediaType'].match('audio') }[0]
object['attachment'] = [{ 'url' => audio_url['href'], 'mediaType' => audio_url['mediaType'] }]
end
object['replies'] = []
threads << object if object['inReplyTo'].nil? || collection.select do |o|
o['id'] == object['inReplyTo']
end.empty?
end
collection.each do |object|
collection.select { |o| o['id'] == object['inReplyTo'] }.each do |o|
o['replies'] << object
end
end
threads.sort_by { |o| o['published'] }.to_json
end
end
post '/delete' do
protected!
params['id'].each do |id|
file = find_file id
FileUtils.rm(file) if File.exist? file
end
end
post '/follow' do
protected!
params['id'] = actor params['mention'] if params['mention']
outbox 'Follow', params['id'], [params['id']]
end
post '/unfollow' do
protected!
params['id'] = actor params['mention'] if params['mention']
following = Dir[File.join(OUTBOX[:dir], 'follow', '*.json')].collect { |f| JSON.parse(File.read(f)) }
activity = following.find { |a| a['object'] == params['id'] }
activity ||= save_activity({ 'type' => 'Follow', 'actor' => ACTOR, 'object' => params['id'] }, OUTBOX) # recreate activity for old/deleted follows
outbox 'Undo', activity, [params['id']]
update_collection FOLLOWING, params['id'], true
end
post '/share' do # TODO
protected!
src = find_file INBOX, params['id']
object = JSON.parse(File.read(src))
recipients = public
recipients << object['attributedTo']
outbox 'Announce', object, recipients
dest = src.sub('/inbox/', '/outbox/')
FileUtils.mkdir_p File.dirname(dest)
FileUtils.mv src, dest
end
post '/login' do
session['client'] = (OpenSSL::Digest::SHA256.base64digest(params['secret']) == File.read('.digest').chomp)
end
helpers do
def protected!
halt 403 unless session['client']
end
def find_file(id)
Dir[File.join('*', 'object', '*', '*.json')].find do |f|
JSON.parse(File.read(f))['id'] == id
end
end
def public
recipients = ['https://www.w3.org/ns/activitystreams#Public']
recipients += JSON.parse(File.read(FOLLOWERS))['orderedItems']
recipients.delete ACTOR
recipients.uniq
end
def parse_follow(follow)
case follow
when /^#/
actor = "https://relay.fedi.buzz/tag/#{follow.sub(/^#/, '')}"
mention = follow
when /^http/
actor = follow
mention = mention(actor)
when /^@*\w+@\w+/
mention = follow
actor = actor(follow)
return 502 unless actor
end
[actor, mention]
end
end
|