summary refs log tree commit diff
diff options
context:
space:
mode:
authorpdp8 <pdp8@pdp8.info>2023-09-09 16:02:50 +0200
committerpdp8 <pdp8@pdp8.info>2023-09-09 16:02:50 +0200
commit3a87028b34c969744f6c63ba73947cfa32156e7d (patch)
tree67b46c322a13b5c3c51c0309d71fe6241876a880
parent9ecb046ed70c9431f97eab1d761aa9fb22f8f73c (diff)
update and clean-inbox added, no outbox send for delete, recursive create for objects with activities (lemmy)
-rw-r--r--application.rb10
-rwxr-xr-xclean-inbox3
-rw-r--r--client.rb23
-rw-r--r--create.rb2
-rw-r--r--helpers.rb9
-rw-r--r--server.rb71
-rwxr-xr-xupdate3
-rwxr-xr-xwatch3
8 files changed, 71 insertions, 53 deletions
diff --git a/application.rb b/application.rb
index a03d98c..5236685 100644
--- a/application.rb
+++ b/application.rb
@@ -1,10 +1,8 @@
-# frozen_string_literal: true
-
 require 'uri'
 require 'base64'
 require 'digest/sha2'
+require 'time'
 require 'rack/protection'
-# require 'rack/contrib'
 require 'sinatra'
 
 SOCIAL_DIR = '/srv/social/'
@@ -25,15 +23,13 @@ INBOX = { dir: File.join(SOCIAL_DIR, 'inbox') }
 OUTBOX = { dir: File.join(SOCIAL_DIR, 'outbox'), url: File.join(SOCIAL_URL, 'outbox') }
 TAGS = { dir: File.join(PUBLIC_DIR, 'tags'), url: File.join(SOCIAL_URL, 'tags') }
 FOLLOWERS_URL = 'https://social.pdp8.info/followers'
+VISITED = File.join(INBOX[:dir], 'visited')
 
+ACTIVITIES = %i[create announce follow accept undo delete like update move]
 CONTENT_TYPE = 'application/activity+json'
 # CONTENT_TYPE = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
 
 use Rack::Protection
-# use Rack::MailExceptions do |mail|
-# mail.to 'info@pdp8.info'
-# mail.smtp false
-# end
 
 enable :sessions
 set :environment, :production
diff --git a/clean-inbox b/clean-inbox
new file mode 100755
index 0000000..b623890
--- /dev/null
+++ b/clean-inbox
@@ -0,0 +1,3 @@
+#!/usr/bin/env nu
+[create announce undo delete like update move] | each { |a| glob $'/srv/social/inbox/($a)/*.json' | each {|f| rm $f } }
+
diff --git a/client.rb b/client.rb
index 61d1ac3..ca5a338 100644
--- a/client.rb
+++ b/client.rb
@@ -10,27 +10,8 @@ post '/delete' do
   protected!
   params['id'].each do |id|
     file = find_file id
-    halt 404 unless file
-    # if file.match(%r{outbox/}) # find/delete activity
-
-    %w[inbox outbox].each do |box|
-      Dir[File.join box, 'announce', '*.json'].each do |announce_file|
-        announce = JSON.load_file(announce_file)
-        next unless announce['object']['id'] == id
-
-        outbox 'Undo', announce, announce['to']
-        FileUtils.rm(announce_file)
-      end
-      Dir[File.join box, 'create', '*.json'].each do |create_file|
-        create = JSON.load_file(create_file)
-        next unless create['object']['id'] == id
-
-        object = JSON.load_file(file)
-        outbox 'Delete', object, object['to']
-        FileUtils.rm(create_file)
-      end
-    end
-    FileUtils.rm(file) if File.exist? file
+    halt 404 unless file and File.exist?(file)
+    FileUtils.rm(file)
   end
   200
 end
diff --git a/create.rb b/create.rb
index 59ef726..12d9a27 100644
--- a/create.rb
+++ b/create.rb
@@ -87,7 +87,7 @@ post '/create' do # TODO
 
   p 'outbox'
   jj object
-  outbox 'Create', object, to
+  # outbox 'Create', object, to
 
   200
 end
diff --git a/helpers.rb b/helpers.rb
index 41dcc33..75221f8 100644
--- a/helpers.rb
+++ b/helpers.rb
@@ -1,5 +1,10 @@
 require 'English'
 helpers do
+  def save_item(item, path)
+    FileUtils.mkdir_p File.dirname(path)
+    File.open(path, 'w+') { |f| f.puts item.to_json }
+  end
+
   # add date and id, save
   def save_activity(activity, box)
     date = Time.now.utc.iso8601
@@ -24,9 +29,7 @@ helpers do
   def save_object(object, box)
     object = fetch(object) if object.is_a? String and object.match(/^http/)
     return unless object and object['type'] != 'Person'
-    # File.open(File.join(INBOX[:dir]), 'visited', 'w+').open { |f| f.puts object['id'] }
-    return if box == INBOX and object['id'] and File.readlines(File.join(INBOX[:dir], 'visited'),
-                                                               chomp: true).include? object['id']
+    return if box == INBOX and object['id'] and File.readlines(VISITED, chomp: true).include? object['id']
 
     object['@context'] = 'https://www.w3.org/ns/activitystreams'
     if object['attributedTo']
diff --git a/server.rb b/server.rb
index 7319efa..68c51e1 100644
--- a/server.rb
+++ b/server.rb
@@ -2,24 +2,16 @@
 post '/inbox' do
   request.body.rewind # in case someone already read it
   @body = request.body.read
-  halt 400 if @body.empty?
   begin
     @activity = JSON.parse @body
-  rescue StandardError
+  rescue StandardError => e
     p @body
     halt 400
   end
   # deleted actors return 403 => verification error
   halt 200 if @activity['type'] == 'Delete' and @activity['actor'] == @activity['object']
   # verify! # pixelfed sends unsigned activities???
-  type = @activity['type'].downcase.to_sym
-  save_activity(@activity, INBOX) # unless %i[create announce].include? type
-  if %i[create announce follow accept undo delete like update move].include? type
-    send(type)
-  else
-    p "Unknown activity #{type}:"
-    jj @activity
-  end
+  handle_activity
   200
 end
 
@@ -66,12 +58,7 @@ helpers do
   def create
     @count ||= 0
     @object ||= @activity['object']
-
-    @object = if @object['type'] == 'Like' # lemmy likes
-                save_object @object['object'], INBOX
-              else
-                save_object @object, INBOX
-              end
+    save_inbox_object
     return unless @object and @object['inReplyTo'] and @count < 5
 
     # recursive thread download
@@ -81,11 +68,14 @@ helpers do
   end
 
   def announce
+    @object ||= @activity['object']
+    @object = fetch(@object) if @object.is_a? String and @object.match(/^http/)
+    @object['announce'] = @activity['actor'] if @object
     create
   end
 
   def like
-    create
+    announce
   end
 
   def follow
@@ -94,8 +84,13 @@ helpers do
   end
 
   def accept
-    halt 501 unless @activity['object']['type'] == 'Follow'
-    update_collection FOLLOWING, @activity['object']['object']
+    if @activity['object']['type'] == 'Follow'
+      update_collection FOLLOWING, @activity['object']['object']
+    else
+      p "Cannot accept @activity['object']['type']"
+      jj @activity
+      halt 501
+    end
   end
 
   def undo
@@ -106,12 +101,15 @@ helpers do
       file = find_file @activity['object']['object']
       FileUtils.rm(file) if file
     else
+      p "Cannot undo @activity['object']['type']"
+      jj @activity
       halt 501
     end
   end
 
   def update
-    FileUtils.rm(find_file(@activity['object']['id']))
+    file = find_file(@activity['object']['id'])
+    FileUtils.rm(file) if file
     create
   end
 
@@ -124,6 +122,39 @@ helpers do
     outbox 'Follow', @activity['target'], [@activity['target']] if @activity['actor'] == @activity['object']
   end
 
+  def handle_activity
+    type = @activity['type'].downcase.to_sym
+    save_item @activity, File.join(INBOX[:dir], @activity['type'].downcase, activity_name)
+    if ACTIVITIES.include? type
+      send(type)
+    else
+      p "Unknown activity #{type}:"
+      jj @activity
+    end
+  end
+
+  def activity_name
+    @activity['published'] ? "#{@activity['published']}_#{mention(@activity['actor'])}.json" : "_#{Time.now.utc.iso8601}_#{mention(@activity['actor'])}.json"
+  end
+
+  def save_inbox_object
+    @object = fetch(@object) if @object.is_a? String and @object.match(/^http/)
+    if @object['type'] and ACTIVITIES.include? @object['type'].downcase.to_sym
+      @activity = @object
+      handle_activity
+      return
+    end
+    # @object = @object['object'] if @object['type'] == 'Like' # lemmy likes
+    return unless @object and @object['type'] != 'Person'
+
+    if @activity['type'] != 'Update' && (@object['id'] and File.readlines(VISITED, chomp: true).include? @object['id'])
+      return
+    end
+
+    save_item @object, File.join(INBOX[:dir], 'object', @object['type'].downcase, activity_name)
+    File.open(File.join(INBOX[:dir], 'visited'), 'a+') { |f| f.puts @object['id'] }
+  end
+
   # https://github.com/mastodon/mastodon/blob/main/app/controllers/concerns/signature_verification.rb
   def verify!
     # digest
diff --git a/update b/update
new file mode 100755
index 0000000..24eebb5
--- /dev/null
+++ b/update
@@ -0,0 +1,3 @@
+#!/bin/sh
+rsync -a --exclude='.git/' --exclude='watch' --exclude='generate-digest.rb' --exclude='update '--exclude='.gitignore' --exclude='TODO' --filter=":- .gitignore" ./ /srv/social/
+sudo systemctl restart social.service
diff --git a/watch b/watch
index 41ad68b..4c020a9 100755
--- a/watch
+++ b/watch
@@ -1,5 +1,6 @@
 #!/bin/sh
 while inotifywait -qq -r ./ -e create,delete,modify; do
-    rsync -a --exclude='.git/' --exclude='watch' --exclude='generate-digest.rb' --exclude='.gitignore' --exclude='TODO' --filter=":- .gitignore" ./ /srv/social/
+    update
+    #rsync -a --exclude='.git/' --exclude='watch' --exclude='generate-digest.rb' --exclude='.gitignore' --exclude='TODO' --filter=":- .gitignore" ./ /srv/social/
     sudo systemctl restart social.service
 done