summaryrefslogtreecommitdiff
path: root/client.rb
blob: b0b638593ce2e0952fffe1f3d432a6d5ec61a5c9 (plain)
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