Skip to content

Commit

Permalink
Add: フレンドサーバー (#61)
Browse files Browse the repository at this point in the history
* Fix mastodon version

* テーブル作成

* Wip: フレンドサーバーフォローの承認を受信

* Wip: フレンド申請拒否を受信

* Wip: フォローリクエストを受理

* Wip: 相手からのフォロー・アンフォローを受理

* 普通のフォローとフレンドサーバーのフォローを区別するテストを追加

* ドメインブロックによるフォロー拒否

* ドメインブロックしたあと、申請中のフォロリクを取り下げる処理

* スタブに条件を追加

* Wip: 相手からのDelete信号に対応

* DB定義が消えていたので修正

* Wip: ローカル公開投稿をフレンドに送信する処理など

* Wip: 未収載+誰でもの投稿をフレンドに送る設定

* Wip: ローカル公開をそのまま送信する設定を考慮

* Fix test

* Wip: 他サーバーからのローカル公開投稿の受け入れ

* Wip: Web画面作成

* Fix test

* Wip: ローカル公開を連合TLに流す

* Wip: フレンドサーバーの削除ボタン

* Wip: メール通知や設定のテストなど

* Wip: 翻訳を作成

* Fix: 却下されたあとフォローボタンが表示されない問題

* Wip: 編集できない問題

* 有効にしていないフレンドサーバーをリストで無効表示
  • Loading branch information
kmycode authored Oct 9, 2023
1 parent acb29e5 commit 87e858a
Show file tree
Hide file tree
Showing 66 changed files with 1,638 additions and 51 deletions.
6 changes: 3 additions & 3 deletions app/controllers/admin/domain_blocks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ def set_domain_block

def update_params
params.require(:domain_block).permit(:severity, :reject_media, :reject_favourite, :reject_reply, :reject_reply_exclude_followers, :reject_send_not_public_searchability, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag,
:reject_straight_follow, :reject_new_follow, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
:reject_straight_follow, :reject_new_follow, :reject_friend, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
end

def resource_params
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_reply_exclude_followers, :reject_send_not_public_searchability, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag,
:reject_straight_follow, :reject_new_follow, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
:reject_straight_follow, :reject_new_follow, :reject_friend, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
end

def form_domain_block_batch_params
params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_reply_exclude_followers, :reject_send_not_public_searchability, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media,
:reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous])
:reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_friend, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous])
end

def action_from_button
Expand Down
89 changes: 89 additions & 0 deletions app/controllers/admin/friend_servers_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# frozen_string_literal: true

module Admin
class FriendServersController < BaseController
before_action :set_friend, except: [:index, :new, :create]
before_action :warn_signatures_not_enabled!, only: [:new, :edit, :create, :follow, :unfollow, :accept, :reject]

def index
authorize :friend_server, :update?
@friends = FriendDomain.all
end

def new
authorize :friend_server, :update?
@friend = FriendDomain.new
end

def edit
authorize :friend_server, :update?
end

def create
authorize :friend_server, :update?

@friend = FriendDomain.new(resource_params)

if @friend.save
@friend.follow!
redirect_to admin_friend_servers_path
else
render action: :new
end
end

def update
authorize :friend_server, :update?

if @friend.update(resource_params)
redirect_to admin_friend_servers_path
else
render action: :edit
end
end

def destroy
authorize :friend_server, :update?
@friend.destroy
redirect_to admin_friend_servers_path
end

def follow
authorize :friend_server, :update?
@friend.follow!
render action: :edit
end

def unfollow
authorize :friend_server, :update?
@friend.unfollow!
render action: :edit
end

def accept
authorize :friend_server, :update?
@friend.accept!
render action: :edit
end

def reject
authorize :friend_server, :update?
@friend.reject!
render action: :edit
end

private

def set_friend
@friend = FriendDomain.find(params[:id])
end

def resource_params
params.require(:friend_domain).permit(:domain, :inbox_url, :available, :pseudo_relay, :unlocked, :allow_all_posts)
end

def warn_signatures_not_enabled!
flash.now[:error] = I18n.t('admin.relays.signatures_not_enabled') if authorized_fetch_mode?
end
end
end
4 changes: 2 additions & 2 deletions app/controllers/api/v1/admin/domain_blocks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def filtered_domain_blocks

def domain_block_params
params.permit(:severity, :reject_media, :reject_favourite, :reject_reply, :reject_reply_exclude_followers, :reject_reports, :reject_send_not_public_searchability, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow,
:reject_new_follow, :detect_invalid_subscription, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
:reject_new_follow, :reject_friend, :detect_invalid_subscription, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
end

def insert_pagination_headers
Expand Down Expand Up @@ -103,6 +103,6 @@ def pagination_params(core_params)

def resource_params
params.permit(:domain, :severity, :reject_media, :reject_favourite, :reject_reply, :reject_reply_exclude_followers, :reject_send_not_public_searchability, :reject_send_public_unlisted, :reject_send_dissubscribable, :reject_send_media, :reject_send_sensitive, :reject_hashtag, :reject_straight_follow,
:reject_new_follow, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
:reject_new_follow, :reject_friend, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden, :hidden_anonymous)
end
end
13 changes: 13 additions & 0 deletions app/lib/activitypub/activity/accept.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class ActivityPub::Activity::Accept < ActivityPub::Activity
def perform
return accept_follow_for_relay if relay_follow?
return accept_follow_for_friend if friend_follow?
return accept_follow!(follow_request_from_object) unless follow_request_from_object.nil?

case @object['type']
Expand Down Expand Up @@ -43,6 +44,18 @@ def relay_follow?
relay.present?
end

def accept_follow_for_friend
friend.update!(active_state: :accepted)
end

def friend
@friend ||= FriendDomain.find_by(domain: @account.domain, active_follow_activity_id: object_uri, active_state: [:pending, :accepted]) if @account.domain.present?
end

def friend_follow?
friend.present?
end

def target_uri
@target_uri ||= value_or_id(@object['actor'])
end
Expand Down
6 changes: 5 additions & 1 deletion app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ def ignore_hashtags?

def related_to_local_activity?
fetch? || followed_by_local_accounts? || requested_through_relay? ||
responds_to_followed_account? || addresses_local_accounts? || quote_local?
responds_to_followed_account? || addresses_local_accounts? || quote_local? || free_friend_domain?
end

def responds_to_followed_account?
Expand Down Expand Up @@ -502,6 +502,10 @@ def quote_local?
end
end

def free_friend_domain?
FriendDomain.free_receivings.exists?(domain: @account.domain)
end

def quote
@quote ||= @object['quote'] || @object['quoteUrl'] || @object['quoteURL'] || @object['_misskey_quote']
end
Expand Down
7 changes: 7 additions & 0 deletions app/lib/activitypub/activity/delete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
def perform
if @account.uri == object_uri
delete_person
elsif object_uri == ActivityPub::TagManager::COLLECTIONS[:public]
delete_friend
else
delete_note
end
Expand Down Expand Up @@ -42,6 +44,11 @@ def delete_note
end
end

def delete_friend
friend = FriendDomain.find_by(domain: @account.domain)
friend&.destroy
end

def forwarder
@forwarder ||= ActivityPub::Forwarder.new(@account, @json, @status)
end
Expand Down
40 changes: 40 additions & 0 deletions app/lib/activitypub/activity/follow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
include Payloadable

def perform
return request_follow_for_friend if friend_follow?

target_account = account_from_uri(object_uri)

return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id'])
Expand Down Expand Up @@ -43,6 +45,36 @@ def reject_follow_request!(target_account)
ActivityPub::DeliveryWorker.perform_async(json, target_account.id, @account.inbox_url)
end

def request_follow_for_friend
already_accepted = false

if friend.present?
already_accepted = friend.they_are_accepted?
friend.update!(passive_state: :pending, passive_follow_activity_id: @json['id'])
else
@friend = FriendDomain.create!(domain: @account.domain, passive_state: :pending, passive_follow_activity_id: @json['id'])
end

if already_accepted || friend.unlocked || Setting.unlocked_friend
friend.accept!
else
# Notify for admin even if unlocked
notify_staff_about_pending_friend_server!
end
end

def friend
@friend ||= FriendDomain.find_by(domain: @account.domain) if @account.domain.present?
end

def friend_follow?
@json['object'] == ActivityPub::TagManager::COLLECTIONS[:public] && !block_friend?
end

def block_friend?
@block_friend ||= DomainBlock.reject_friend?(@account.domain) || DomainBlock.blocked?(@account.domain)
end

def block_straight_follow?
@block_straight_follow ||= DomainBlock.reject_straight_follow?(@account.domain)
end
Expand Down Expand Up @@ -73,4 +105,12 @@ def proxyable_software?
def instance_info
@instance_info ||= InstanceInfo.find_by(domain: @account.domain)
end

def notify_staff_about_pending_friend_server!
User.those_who_can(:manage_federation).includes(:account).find_each do |u|
next unless u.allows_pending_friend_server_emails?

AdminMailer.with(recipient: u.account).new_pending_friend_server(friend).deliver_later
end
end
end
13 changes: 13 additions & 0 deletions app/lib/activitypub/activity/reject.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class ActivityPub::Activity::Reject < ActivityPub::Activity
def perform
return reject_follow_for_relay if relay_follow?
return reject_follow_for_friend if friend_follow?
return follow_request_from_object.reject! unless follow_request_from_object.nil?
return UnfollowService.new.call(follow_from_object.account, @account) unless follow_from_object.nil?

Expand Down Expand Up @@ -37,6 +38,18 @@ def relay_follow?
relay.present?
end

def reject_follow_for_friend
friend.update!(active_state: :rejected)
end

def friend
@friend ||= FriendDomain.find_by(domain: @account.domain, active_follow_activity_id: object_uri, active_state: [:pending, :accepted]) if @account.domain.present?
end

def friend_follow?
friend.present?
end

def target_uri
@target_uri ||= value_or_id(@object['actor'])
end
Expand Down
14 changes: 14 additions & 0 deletions app/lib/activitypub/activity/undo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def undo_accept
end

def undo_follow
return remove_follow_from_friend if friend_follow?

target_account = account_from_uri(target_uri)

return if target_account.nil? || !target_account.local?
Expand All @@ -100,6 +102,18 @@ def undo_follow
end
end

def remove_follow_from_friend
friend.update!(passive_state: :idle, passive_follow_activity_id: nil)
end

def friend
@friend ||= FriendDomain.find_by(domain: @account.domain) if @account.domain.present? && @object['object'] == ActivityPub::TagManager::COLLECTIONS[:public]
end

def friend_follow?
friend.present?
end

def undo_like_original
status = status_from_uri(target_uri)

Expand Down
4 changes: 4 additions & 0 deletions app/lib/activitypub/parser/status_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def sensitive
def visibility
if audience_to.any? { |to| ActivityPub::TagManager.instance.public_collection?(to) }
:public
elsif audience_to.include?('LocalPublic')
:public_unlisted
elsif audience_cc.any? { |cc| ActivityPub::TagManager.instance.public_collection?(cc) }
:unlisted
elsif audience_to.include?('as:LoginOnly') || audience_to.include?('LoginUser')
Expand Down Expand Up @@ -198,6 +200,8 @@ def searchability_from_audience
:public
elsif audience_searchable_by.include?('as:Limited')
:limited
elsif audience_searchable_by.include?('LocalPublic')
:public_unlisted
elsif audience_searchable_by.include?(@account.followers_url)
:private
else
Expand Down
14 changes: 13 additions & 1 deletion app/lib/activitypub/tag_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ def to(status)
end
end

def to_for_friend(status)
to = to(status)
to << 'LocalPublic' if status.public_unlisted_visibility?
to
end

# Secondary audience of a status
# Public statuses go out to followers as well
# Unlisted statuses go to the public as well
Expand All @@ -147,7 +153,7 @@ def cc(status)
end

def cc_for_misskey(status)
if (status.account.user&.setting_reject_unlisted_subscription && status.visibility == 'unlisted') || (status.account.user&.setting_reject_public_unlisted_subscription && status.visibility == 'public_unlisted')
if (status.account.user&.setting_reject_unlisted_subscription && status.unlisted_visibility?) || (status.account.user&.setting_reject_public_unlisted_subscription && status.public_unlisted_visibility?)
cc = cc_private_visibility(status)
cc << uri_for(status.reblog.account) if status.reblog?
return cc
Expand Down Expand Up @@ -251,6 +257,12 @@ def searchable_by(status)
searchable_by.concat(mentions_uris(status)).compact
end

def searchable_by_for_friend(status)
searchable = searchable_by(status)
searchable << 'LocalPublic' if status.compute_searchability_local == 'public_unlisted'
searchable
end

def account_searchable_by(account)
case account.compute_searchability_activitypub
when 'public'
Expand Down
Loading

0 comments on commit 87e858a

Please sign in to comment.