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