diff options
-rw-r--r-- | client.rb | 3 | ||||
-rw-r--r-- | helpers.rb | 35 | ||||
-rw-r--r-- | server.rb | 47 |
3 files changed, 51 insertions, 34 deletions
@@ -140,6 +140,9 @@ end get path, provides: 'html' do protected! @dir = path.sub('/', '') + # collection = DirI# + # collection = Dir[File.join(@dir, 'object','*', '*.json')].collect { |f| JSON.parse(File.read(f)) } + @collection = Dir[File.join(@dir, 'create', '*.json')].collect { |f| JSON.parse(File.read(f))['object'] } @collection += Dir[File.join(@dir, 'announce', '*.json')].collect { |f| JSON.parse(File.read(f))['object'] } @threads = [] @@ -4,34 +4,36 @@ require 'English' helpers do # add date and id, save - def complete_and_save(activity) - box = activity['id'] ? INBOX : OUTBOX + def save_activity(activity, box) date = Time.now.utc.iso8601 activity['published'] = date if box == OUTBOX basename = "#{activity['published']}_#{mention(activity['actor'])}.json" activity_rel_path = File.join(activity['type'].downcase, basename) activity_path = File.join(box[:dir], activity_rel_path) - activity['id'] = File.join(box[:url], activity_rel_path) if box == OUTBOX - - if activity['object'] && activity['object']['type'] && !activity['object']['id'] - # save object - object = activity['object'] - object['@context'] = 'https://www.w3.org/ns/activitystreams' - object_rel_path = File.join 'object', activity['object']['type'].downcase, basename - if box == OUTBOX - object['id'] = File.join box[:url], object_rel_path - object['published'] = date - end - object_path = File.join box[:dir], object_rel_path - FileUtils.mkdir_p File.dirname(object_path) - File.open(object_path, 'w+') { |f| f.puts object.to_json } + if box == OUTBOX + activity['id'] = File.join(box[:url], activity_rel_path) + activity['object']['published'] = date end + # save object + save_object activity['object'], box if activity['object'] && activity['object']['type'] && !activity['object']['id'] # save activity FileUtils.mkdir_p File.dirname(activity_path) File.open(activity_path, 'w+') { |f| f.puts activity.to_json } activity end + def save_object(object, box) + object = fetch(object) if object.is_a? String and object.match(/^http/) + object['@context'] = 'https://www.w3.org/ns/activitystreams' + basename = "#{object['published']}_#{mention(object['attributedTo'])}.json" + object_rel_path = File.join 'object', object['type'].downcase, basename + object['id'] = File.join box[:url], object_rel_path if box == OUTBOX + object_path = File.join box[:dir], object_rel_path + FileUtils.mkdir_p File.dirname(object_path) + File.open(object_path, 'w+') { |f| f.puts object.to_json } + object + end + def update_collection(path, objects, delete = false) objects = [objects] unless objects.is_a? Array File.open(path, 'r+') do |f| @@ -61,7 +63,6 @@ helpers do string = "(request-target): get #{uri.request_uri}\nhost: #{uri.host}\ndate: #{httpdate}" signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), string)) signed_header = "keyId=\"#{ACTOR}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date\",signature=\"#{signature}\"" - response = curl( "-H 'Accept: #{accept}' -H 'Host: #{uri.host}' -H 'Date: #{httpdate}' -H 'Signature: #{signed_header}' ", url ) @@ -13,9 +13,9 @@ post '/inbox' do end halt 501 if @activity['actor'] and @activity['type'] == 'Delete' # deleted actors return 403 => verification error verify! # unless type == :accept # pixelfed sends unsigned accept activities??? - complete_and_save(@activity) + save_activity(@activity, INBOX) type = @activity['type'].downcase.to_sym - send(type) if %i[follow accept undo].include? type + send(type) if %i[create announce follow accept undo].include? type halt 200 end @@ -36,6 +36,19 @@ end end helpers do + def create + @object ||= @activity['object'] + @object = save_object @object, INBOX + return unless @object['inReplyTo'] + + @object = @object['inReplyTo'] + create + end + + def announce + create + end + def follow update_collection FOLLOWERS, @activity['actor'] outbox 'Accept', @activity, [@activity['actor']] @@ -88,22 +101,8 @@ helpers do end def outbox(type, object, recipients) - # add date and id, save - activity = complete_and_save({ - '@context' => 'https://www.w3.org/ns/activitystreams', - 'type' => type, - 'actor' => ACTOR, - 'object' => object, - 'to' => recipients - }) - # send - # https://github.com/mastodon/mastodon/blob/main/app/lib/request.rb - keypair = OpenSSL::PKey::RSA.new(File.read('private.pem')) - body = activity.to_json - sha256 = OpenSSL::Digest.new('SHA256') - digest = "SHA-256=#{sha256.base64digest(body)}" - + ## https://github.com/mastodon/mastodon/blob/main/app/lib/request.rb inboxes = [] recipients.uniq.each do |url| next if [ACTOR, 'https://www.w3.org/ns/activitystreams#Public'].include? url @@ -118,8 +117,22 @@ helpers do end end + # add date and id, save + activity = save_activity({ + '@context' => 'https://www.w3.org/ns/activitystreams', + 'type' => type, + 'actor' => ACTOR, + 'object' => object, + 'to' => recipients + }, OUTBOX) + body = activity.to_json + sha256 = OpenSSL::Digest.new('SHA256') + digest = "SHA-256=#{sha256.base64digest(body)}" + keypair = OpenSSL::PKey::RSA.new(File.read('private.pem')) + inboxes.compact.uniq.each do |inbox| uri = URI(inbox) + httpdate = Time.now.utc.httpdate string = "(request-target): post #{uri.request_uri}\nhost: #{uri.host}\ndate: #{httpdate}\ndigest: #{digest}\ncontent-type: application/activity+json" signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), string)) signed_header = "keyId=\"#{ACTOR}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"#{signature}\"" |