# frozen_string_literal: true
# client-server
post '/' do
protected!
Time.now.strftime('%Y-%m-%dT%H:%M:%S.%N')
recipients = public
recipients << params[:to]
content = []
attachment = []
tag = []
extensions = {
image: %w[jpeg png],
audio: %w[flac wav mp3 ogg],
video: %w[mp4 webm]
}
params[:content].lines.each do |line|
line.chomp!
if line.match(/^http/)
ext = File.extname(line).sub('.', '')
media_type = extensions.select { |_k, v| v.include? ext }.keys[0].to_s + '/' + ext
attachment << {
'type' => 'Document',
'mediaType' => media_type,
'url' => line
}
else
tags = line.split(/\s+/).grep(/^#\w+$/)
tags.each do |name|
href = File.join(SOCIAL_URL, 'tags', name.sub('#', ''))
tag << {
'type' => 'Hashtag',
'href' => href,
'name' => name
}
line.gsub!(name, "#{name}")
end
content << line
end
end
object = {
'type' => 'Note',
'attributedTo' => ACTOR,
'inReplyTo' => params[:inReplyTo],
'content' => "
\n#{content.join("\n
")}\n
",
'attachment' => attachment,
'tag' => tag,
'to' => recipients
}
outbox 'Create', object, recipients, true
redirect(params['anchor'] || '/inbox')
end
post '/share' do
protected!
selection(params).each { |f| FileUtils.mv f, f.sub(%r{/inbox/}, '/shared/') }
outbox 'Announce', params['id'], public
redirect(params['anchor'] || '/inbox')
end
post '/delete' do
protected!
selection(params).each { |f| FileUtils.rm f }
redirect(params['anchor'] || '/inbox')
end
post '/follow' do
protected!
actor, = parse_follow params['follow']
outbox 'Follow', actor, [actor]
redirect(params['anchor'] || '/inbox')
end
post '/unfollow' do
protected!
actor, mention = parse_follow params['follow']
following_path = File.join(FOLLOWING_DIR, "#{mention}.json")
if File.exist?(following_path)
outbox 'Undo', JSON.parse(File.read(following_path)), [actor]
FileUtils.rm_f following_path
redirect(params['anchor'] || '/inbox')
end
end
post '/login' do
session['client'] = (OpenSSL::Digest::SHA256.base64digest(params['secret']) == File.read('.digest').chomp)
redirect '/inbox'
end
get '/' do
protected!
redirect '/inbox'
end
['/inbox', '/shared', '/outbox'].each do |path|
get path, provides: 'html' do
protected!
@dir = path.sub('/', '')
collection = ordered_collection(File.join(SOCIAL_DIR, path, 'note'))['orderedItems']
@threads = []
collection.each_with_index do |object, _idx|
object['indent'] = 0
object['replies'] = []
if object['inReplyTo'].nil? || collection.select { |o| o['id'] == object['inReplyTo'] }.empty?
@threads << object
else
collection.select { |o| o['id'] == object['inReplyTo'] }.each do |o|
object['indent'] = o['indent'] + 2
o['replies'] << object
end
end
end
erb :collection
end
end
helpers do
def protected!
halt 403 unless session['client']
end
def selection(params)
selection = Dir[File.join(SOCIAL_DIR, params['dir'], '*', '*.json')]
params['id'] ? selection.select { |f| JSON.parse(File.read(f))['id'] == params['id'] } : selection
end
def public
recipients = ['https://www.w3.org/ns/activitystreams#Public']
recipients += Dir[File.join(FOLLOWERS, '*.json')].collect { |f| JSON.parse(File.read(f))['actor'] }
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