# client-server post "/" do protected! date = Time.now.strftime("%Y-%m-%dT%H:%M:%S") outbox_path = File.join("public/outbox", date + ".json") notes_path = File.join("public/notes", date + ".json") recipients = ["https://www.w3.org/ns/activitystreams#Public", params[:to]] recipients += Dir[File.join("public/followers", "*.json")].collect { |f| JSON.parse(File.read(f))["actor"] } recipients.delete ACTOR recipients.uniq! content = [] attachment = [] tag = [] extensions = { :image => ["jpeg","png"], :audio => ["flac","wav","mp3","ogg"], :video => ["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, "") end content << line end end create = { "@context" => "https://www.w3.org/ns/activitystreams", "id" => File.join(SOCIAL_URL, outbox_path), "type" => "Create", "actor" => ACTOR, "object" => { "id" => File.join(SOCIAL_URL, notes_path), "type" => "Note", "attributedTo" => ACTOR, "inReplyTo" => params[:inReplyTo], "published" => date, "content" => "

\n"+content.join("\n
")+"\n

", "attachment" => attachment, "tag" => tag, "to" => recipients }, "published" => date, "to" => recipients } File.open(outbox_path, "w+") { |f| f.puts create.to_json } File.open(notes_path, "w+") { |f| f.puts create["object"].to_json } tag.each do |t| dir = File.join('public','tags',t['name'].sub('#','')) FileUtils.mkdir_p dir FileUtils.ln_s File.join('/srv/social/',notes_path), dir end #recipients.delete "https://www.w3.org/ns/activitystreams#Public" #recipients.each { |r| send_signed create, r } send_signed create #, r } redirect params['redirect'] end post "/archive" do protected! FileUtils.mv params['file'], "archive/" redirect to(params['redirect']) end post "/delete" do # delete not supported by html forms protected! params['file'] ? FileUtils.rm_f(params['file']) : FileUtils.rm_f(Dir["inbox/*.json"]) params['redirect'] ? redirect(params['redirect']) : redirect('/') end post "/follow" do protected! actor, mention = parse_follow params['follow'] follow = { "@context" => "https://www.w3.org/ns/activitystreams", "id" => File.join(SOCIAL_URL, "following", mention+ ".json"), "type" => "Follow", "actor" => ACTOR, "object" => actor, 'to' => [ actor ] } send_signed follow#, actor redirect "/" end post "/unfollow" do protected! actor, mention = parse_follow params['follow'] following_path = File.join("public", "following", mention + ".json") if File.exists?(following_path) undo = { "@context" => "https://www.w3.org/ns/activitystreams", "id" => File.join(SOCIAL_URL + "#undo", SecureRandom.uuid), "type" => "Undo", "actor" => ACTOR, "object" => JSON.parse(File.read(following_path)), 'to' => [ actor ] } send_signed undo#, actor FileUtils.rm following_path redirect "/" end end post "/login" do session["client"] = true if OpenSSL::Digest::SHA256.base64digest(params["secret"]) == File.read(".digest").chomp redirect "/" end # private ["/", "/archive"].each do |path| get path, :provides => 'html' do protected! if path == '/' @dir = 'inbox' @alt_dir = '/archive' @alt_name = 'archive' else @dir = path.sub('/','') @alt_dir = '/' @alt_name = 'inbox' end threads erb :index end end helpers do def protected! halt 403 unless session['client'] end def items nr = 0 p @dir p Dir[File.join(@dir, '*', '*.json')]# + Dir['public/notes/*.json'] files = Dir[File.join(@dir, '*', '*.json')] + Dir['public/notes/*.json'] @items = files.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 => 0, :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] + 4 it[:replies] << i end end end end def html item @item = item erb :item 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