From dd7ef0dc41584089a97444d8192bc61505108e6c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Aug 2017 21:52:15 +0200 Subject: Add ActivityPub inbox (#4216) * Add ActivityPub inbox * Handle ActivityPub deletes * Handle ActivityPub creates * Handle ActivityPub announces * Stubs for handling all activities that need to be handled * Add ActivityPub actor resolving * Handle conversation URI passing in ActivityPub * Handle content language in ActivityPub * Send accept header when fetching actor, handle JSON parse errors * Test for ActivityPub::FetchRemoteAccountService * Handle public key and icon/image when embedded/as array/as resolvable URI * Implement ActivityPub::FetchRemoteStatusService * Add stubs for more interactions * Undo activities implemented * Handle out of order activities * Hook up ActivityPub to ResolveRemoteAccountService, handle Update Account activities * Add fragment IDs to all transient activity serializers * Add tests and fixes * Add stubs for missing tests * Add more tests * Add more tests --- app/lib/activitypub/activity/follow.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/lib/activitypub/activity/follow.rb (limited to 'app/lib/activitypub/activity/follow.rb') diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb new file mode 100644 index 000000000..7918b5108 --- /dev/null +++ b/app/lib/activitypub/activity/follow.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Follow < ActivityPub::Activity + def perform + target_account = account_from_uri(object_uri) + + return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) + + follow = @account.follow!(target_account) + NotifyService.new.call(target_account, follow) + end +end -- cgit From 81c1303cd6137c8c90794cc0bfdc1a0479eb2153 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 10 Aug 2017 22:33:12 +0200 Subject: Handle ActivityPub follows correctly (#4571) * Handle ActivityPub follows correctly ActivityPub follows are follow-requests. Always require an Accept. If account is not locked, auto-accept. * Handle ActivityPub Accept/Reject-Follow * Fix wrong method * Fix wrong class --- app/lib/activitypub/activity.rb | 4 ++++ app/lib/activitypub/activity/accept.rb | 25 +++++++++++++++++++++++++ app/lib/activitypub/activity/follow.rb | 10 ++++++++-- app/lib/activitypub/activity/reject.rb | 25 +++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 app/lib/activitypub/activity/accept.rb create mode 100644 app/lib/activitypub/activity/reject.rb (limited to 'app/lib/activitypub/activity/follow.rb') diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index d1b81a582..5debe023a 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -39,6 +39,10 @@ class ActivityPub::Activity ActivityPub::Activity::Update when 'Undo' ActivityPub::Activity::Undo + when 'Accept' + ActivityPub::Activity::Accept + when 'Reject' + ActivityPub::Activity::Reject end end end diff --git a/app/lib/activitypub/activity/accept.rb b/app/lib/activitypub/activity/accept.rb new file mode 100644 index 000000000..f5880937a --- /dev/null +++ b/app/lib/activitypub/activity/accept.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Accept < ActivityPub::Activity + def perform + case @object['type'] + when 'Follow' + accept_follow + end + end + + private + + def accept_follow + target_account = account_from_uri(target_uri) + + return if target_account.nil? || !target_account.local? + + follow_request = FollowRequest.find_by(account: target_account, target_account: @account) + follow_request&.authorize! + end + + def target_uri + @target_uri ||= @object['object'].is_a?(String) ? @object['object'] : @object['object']['id'] + end +end diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 7918b5108..3fb698d1d 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -6,7 +6,13 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) - follow = @account.follow!(target_account) - NotifyService.new.call(target_account, follow) + follow_request = FollowRequest.create!(account: @account, target_account: target_account) + + if target_account.locked? + NotifyService.new.call(target_account, follow_request) + else + AuthorizeFollowService.new.call(@account, target_account) + NotifyService.new.call(target_account, ::Follow.find_by(account: @account, target_account: target_account)) + end end end diff --git a/app/lib/activitypub/activity/reject.rb b/app/lib/activitypub/activity/reject.rb new file mode 100644 index 000000000..78dbfd1e5 --- /dev/null +++ b/app/lib/activitypub/activity/reject.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Reject < ActivityPub::Activity + def perform + case @object['type'] + when 'Follow' + reject_follow + end + end + + private + + def reject_follow + target_account = account_from_uri(target_uri) + + return if target_account.nil? || !target_account.local? + + follow_request = FollowRequest.find_by(account: target_account, target_account: @account) + follow_request&.reject! + end + + def target_uri + @target_uri ||= @object['object'].is_a?(String) ? @object['object'] : @object['object']['id'] + end +end -- cgit From fe5b66aa0870212e27a6632fb9c83a2d16bd99ab Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 20 Aug 2017 16:53:47 +0200 Subject: Handle duplicate ActivityPub activities (#4639) * Handle duplicate ActivityPub activities Only perform side-effects when record processed for the first time * Fast-forward repeat follow requests --- app/lib/activitypub/activity/announce.rb | 4 ++++ app/lib/activitypub/activity/block.rb | 2 +- app/lib/activitypub/activity/follow.rb | 8 +++++++- app/lib/activitypub/activity/like.rb | 4 ++-- app/services/authorize_follow_service.rb | 11 ++++++++--- 5 files changed, 22 insertions(+), 7 deletions(-) (limited to 'app/lib/activitypub/activity/follow.rb') diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb index 09fec28a0..c4da405c7 100644 --- a/app/lib/activitypub/activity/announce.rb +++ b/app/lib/activitypub/activity/announce.rb @@ -7,6 +7,10 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity return if original_status.nil? || delete_arrived_first?(@json['id']) + status = Status.find_by(account: @account, reblog: original_status) + + return status unless status.nil? + status = Status.create!(account: @account, reblog: original_status, uri: @json['id']) distribute(status) status diff --git a/app/lib/activitypub/activity/block.rb b/app/lib/activitypub/activity/block.rb index e6b6c837b..f630d5db2 100644 --- a/app/lib/activitypub/activity/block.rb +++ b/app/lib/activitypub/activity/block.rb @@ -4,7 +4,7 @@ class ActivityPub::Activity::Block < ActivityPub::Activity def perform target_account = account_from_uri(object_uri) - return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) + return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.blocking?(target_account) UnfollowService.new.call(target_account, @account) if target_account.following?(@account) @account.block!(target_account) diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 3fb698d1d..8adbbb9c3 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -4,7 +4,13 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity def perform target_account = account_from_uri(object_uri) - return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) + return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account) + + # Fast-forward repeat follow requests + if @account.following?(target_account) + AuthorizeFollowService.new.call(@account, target_account, skip_follow_request: true) + return + end follow_request = FollowRequest.create!(account: @account, target_account: target_account) diff --git a/app/lib/activitypub/activity/like.rb b/app/lib/activitypub/activity/like.rb index c24527597..674d5fe47 100644 --- a/app/lib/activitypub/activity/like.rb +++ b/app/lib/activitypub/activity/like.rb @@ -4,9 +4,9 @@ class ActivityPub::Activity::Like < ActivityPub::Activity def perform original_status = status_from_uri(object_uri) - return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) + return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) || @account.favourited?(original_status) - favourite = original_status.favourites.where(account: @account).first_or_create!(account: @account) + favourite = original_status.favourites.create!(account: @account) NotifyService.new.call(original_status.account, favourite) end end diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb index db35b6030..6f036dc5a 100644 --- a/app/services/authorize_follow_service.rb +++ b/app/services/authorize_follow_service.rb @@ -1,9 +1,14 @@ # frozen_string_literal: true class AuthorizeFollowService < BaseService - def call(source_account, target_account) - follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) - follow_request.authorize! + def call(source_account, target_account, options = {}) + if options[:skip_follow_request] + follow_request = FollowRequest.new(account: source_account, target_account: target_account) + else + follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) + follow_request.authorize! + end + create_notification(follow_request) unless source_account.local? follow_request end -- cgit