diff options
-rw-r--r-- | client.rb | 29 | ||||
-rw-r--r-- | create.rb | 6 | ||||
-rw-r--r-- | helpers.rb | 9 | ||||
-rw-r--r-- | server.rb | 81 | ||||
-rwxr-xr-x | watch | 2 |
5 files changed, 51 insertions, 76 deletions
@@ -9,7 +9,7 @@ end post '/delete' do protected! params['id'].each do |id| - file = find_file id + file, object = find_object id halt 404 unless file and File.exist?(file) FileUtils.rm(file) end @@ -53,20 +53,19 @@ post '/share' do # TODO 200 end -# post '/undo' do # TODO: generalize for announce -# protected! -# activity_file = find_file(params['id']) -# Dir[File.join('outbox', '*', '*.json')].each do |f| -# activity = JSON.load_file(f) -# next unless activity['id'] == params['id'] -# -# object_file = find_file activity['object']['id'] -# create_activity 'Undo', params['id'], activity['to'] -# FileUtils.rm(object_file) -# FileUtils.rm(f) -# end -# 200 -# end +post '/undo' do # TODO: generalize for announce + protected! + Dir[File.join('outbox', '*', '*.json')].each do |activity_file| + activity = JSON.load_file(activity_file) + next unless activity['id'] == params['id'] + + object_file = find_file activity['object']['id'] + create_activity 'Undo', params['id'], activity['to'] + FileUtils.rm(activity_file) + FileUtils.rm(object_file) + end + 200 +end post '/login' do session['client'] = (OpenSSL::Digest::SHA256.base64digest(params['secret']) == File.read('.digest').chomp) @@ -37,15 +37,17 @@ post '/create' do when REPLY_REGEXP inReplyTo = line.sub(REPLY_REGEXP, '') when ATTACH_REGEXP - url = line.sub(ATTACH_REGEXP, '') + url, description = line.sub(ATTACH_REGEXP, '').split(/\s+/, 2) attachment << { 'type' => 'Document', 'mediaType' => media_type(url), - 'url' => url + 'url' => url, + 'name' => description } else # create links # single quotes in html invalidate digest, reason unknown line.split(/\s+/).each do |word| + word = word.gsub('<p>', '').gsub('</p>', '') case word when HASHTAG_REGEXP tag_url = File.join('https://social.pdp8.info', 'tags', word.sub('#', '')) @@ -80,7 +80,6 @@ helpers do 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}\"" - p inbox # Net::HTTP fails with OpenSSL error curl( "-X POST -H 'Host: #{uri.host}' -H 'Date: #{httpdate}' -H 'Digest: #{digest}' -H 'Signature: #{signed_header}' --data-binary '@#{activity_path}'", inbox @@ -204,8 +203,14 @@ helpers do def find_file(id) Dir[File.join('*', 'object', '*', '*.json')].find do |f| - # Dir[File.join('*box', '**', '*.json')].find do |f| JSON.load_file(f)['id'] == id end end + + def find_object(id) + Dir[File.join('*', '**', '*.json')].each do |file| + object = JSON.load_file(file) + return [file, object] if object['id'] == id + end + end end @@ -82,11 +82,13 @@ helpers do end def follow + save_item @activity, File.join(INBOX[:dir], @activity['type'].downcase, activity_name) update_collection FOLLOWERS, @activity['actor'] create_activity 'Accept', @activity, [@activity['actor']] end def accept + save_item @activity, File.join(INBOX[:dir], @activity['type'].downcase, activity_name) if @activity['object']['type'] == 'Follow' update_collection FOLLOWING, @activity['object']['object'] else @@ -131,13 +133,15 @@ helpers do if ACTIVITIES.include? type send(type) else - p "Unknown activity #{type}:" - jj @activity + unless %w[Add Remove].include? @activity['type'] + p "Unknown activity #{type}:" + jj @activity + end end end def activity_name - @activity['published'] ? "#{@activity['published']}_#{mention(@activity['actor'])}.json" : "_#{Time.now.utc.iso8601}_#{mention(@activity['actor'])}.json" + @activity['published'] ? "#{@activity['published']}_#{mention(@activity['actor'])}.json" : "#{Time.now.utc.iso8601}_#{mention(@activity['actor'])}.json" end def save_inbox_object @@ -155,15 +159,12 @@ helpers do end def public_outbox - # files = Dir[File.join('outbox', 'create', '*.json')] + Dir[File.join('outbox', 'announce', '*.json')] create = Dir[File.join('outbox', 'create', '*.json')].collect do |f| JSON.load_file(f) end.select { |a| a['to'].include?('https://www.w3.org/ns/activitystreams#Public') }.sort_by { |a| a['published'] }.reverse announce = Dir[File.join('outbox', 'announce', '*.json')].collect do |f| JSON.load_file(f) end.select { |a| a['to'].include?('https://www.w3.org/ns/activitystreams#Public') }.sort_by { |a| a['published'] }.reverse - # activities = files.collect { |f| JSON.load_file(f) } - # activities.select { |a| a['to'].include?('https://www.w3.org/ns/activitystreams#Public') }.sort_by { |a| a['published'] } create + announce end @@ -172,7 +173,11 @@ helpers do # digest sha256 = OpenSSL::Digest.new('SHA256') digest = "SHA-256=#{sha256.base64digest(@body)}" - halt 403 unless digest == request.env['HTTP_DIGEST'] + unless digest == request.env['HTTP_DIGEST'] + p 'invalid digest' + p @body + halt 403 + end # signature signature_params = {} @@ -186,7 +191,11 @@ helpers do signature = Base64.decode64(signature_params['signature']) actor = fetch key_id - halt 403 unless actor + unless actor + p 'no actor' + jj @activity + halt 403 + end key = OpenSSL::PKey::RSA.new(actor['publicKey']['publicKeyPem']) @@ -200,51 +209,13 @@ helpers do end end.join("\n") - halt 403 unless key.verify(OpenSSL::Digest.new('SHA256'), signature, comparison) - end - - # def outbox(type, object, to) # https://github.com/mastodon/mastodon/blob/main/app/lib/request.rb - # to = [to] if to.is_a?(String) - # inboxes = [] - # to.uniq.each do |url| - # next if [ACTOR, 'https://www.w3.org/ns/activitystreams#Public'].include? url - # - # if url == FOLLOWERS_URL - # JSON.load_file(FOLLOWERS)['orderedItems'].each do |follower| - # inboxes << actor_inbox(follower) - # end - # next - # end - # inboxes << actor_inbox(url) - # end - # - # # add date and id, save - # activity_path = save_activity({ - # '@context' => 'https://www.w3.org/ns/activitystreams', - # 'type' => type, - # 'actor' => ACTOR, - # 'object' => object, - # 'to' => to - # }, OUTBOX) - # - # # p activity_path - # body = File.read(activity_path) - # 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: #{CONTENT_TYPE}" - # 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}\"" - # - # # Net::HTTP fails with OpenSSL error - # curl( - # "-X POST -H 'Host: #{uri.host}' -H 'Date: #{httpdate}' -H 'Digest: #{digest}' -H 'Signature: #{signed_header}' --data-binary '@#{activity_path}'", inbox - # ) - # end - # activity_path - # end + return if key.verify(OpenSSL::Digest.new('SHA256'), signature, comparison) + + p 'verification failed' + p signature_params + p actor['publicKey'] + p signature, comparison + jj @activity + # halt 403 + end end @@ -1,6 +1,4 @@ #!/bin/sh while inotifywait -qq -r ./ -e create,delete,modify; do ./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 |