Skip to content

Commit a50d5db

Browse files
ClearlyClairehiyuki2578
authored andcommitted
Add ActivityPub actor representing the entire server (mastodon#11321)
* Add support for an instance actor * Skip username validation for local Application accounts * Add migration script to create instance actor * Make Codeclimate happy * Switch to id -99 for instance actor * Remove unused `icon` and `image` attributes from instance actor * Use if/elsif/else instead of return + ternary operator * Add instance actor to fresh installs * Use instance actor as instance representative Use instance actor for forwarding reports, relay operations, and spam auto-reporting. * Seed database in test environment * Fix single-user mode * Fix tests * Fix specs to accomodate for an extra `Account` * Auto-reject follows on instance actor Following an instance actor might make sense, but we are not handling that right now, so auto-reject. * Fix webfinger lookup and serialization for instance actor * Rename instance actor * Make it clear in the HTML view that the instance actor should not be blocked * Raise cache time for instance actor as there's no dynamic content * Re-use /about/more with a flash message for instance actor profile
1 parent f647b85 commit a50d5db

23 files changed

Lines changed: 141 additions & 52 deletions

app/controllers/about_controller.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ class AboutController < ApplicationController
1111

1212
def show; end
1313

14-
def more; end
14+
def more
15+
flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
16+
end
1517

1618
def terms; end
1719

app/controllers/application_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def not_acceptable
9191
end
9292

9393
def single_user_mode?
94-
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.exists?
94+
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
9595
end
9696

9797
def use_seamless_external_login?

app/controllers/home_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def default_redirect_path
5858
if request.path.start_with?('/web')
5959
new_user_session_path
6060
elsif single_user_mode?
61-
short_account_path(Account.local.without_suspended.first)
61+
short_account_path(Account.local.without_suspended.where('id > 0').first)
6262
else
6363
about_path
6464
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
class InstanceActorsController < ApplicationController
4+
include AccountControllerConcern
5+
6+
def show
7+
expires_in 10.minutes, public: true
8+
render json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, fields: restrict_fields_to
9+
end
10+
11+
private
12+
13+
def set_account
14+
@account = Account.find(-99)
15+
end
16+
17+
def restrict_fields_to
18+
%i(id type preferred_username inbox public_key endpoints url manually_approves_followers)
19+
end
20+
end

app/javascript/styles/mastodon/containers.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@
145145
min-height: 100%;
146146
}
147147

148+
.flash-message {
149+
margin-bottom: 10px;
150+
}
151+
148152
@media screen and (max-width: 738px) {
149153
grid-template-columns: minmax(0, 50%) minmax(0, 50%);
150154

app/lib/activitypub/activity/follow.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def perform
88

99
return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)
1010

11-
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved?
11+
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor?
1212
reject_follow_request!(target_account)
1313
return
1414
end

app/lib/activitypub/tag_manager.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def url_for(target)
1717

1818
case target.object_type
1919
when :person
20-
short_account_url(target)
20+
target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target)
2121
when :note, :comment, :activity
2222
return activity_account_status_url(target.account, target) if target.reblog?
2323
short_account_status_url(target.account, target)
@@ -29,7 +29,7 @@ def uri_for(target)
2929

3030
case target.object_type
3131
when :person
32-
account_url(target)
32+
target.instance_actor? ? instance_actor_url : account_url(target)
3333
when :note, :comment, :activity
3434
return activity_account_status_url(target.account, target) if target.reblog?
3535
account_status_url(target.account, target)
@@ -119,6 +119,7 @@ def local_uri?(uri)
119119

120120
def uri_to_local_id(uri, param = :id)
121121
path_params = Rails.application.routes.recognize_path(uri)
122+
path_params[:username] = Rails.configuration.x.local_domain if path_params[:controller] == 'instance_actors'
122123
path_params[param]
123124
end
124125

app/lib/webfinger_resource.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@ def username
2323
def username_from_url
2424
if account_show_page?
2525
path_params[:username]
26+
elsif instance_actor_page?
27+
Rails.configuration.x.local_domain
2628
else
2729
raise ActiveRecord::RecordNotFound
2830
end
2931
end
3032

33+
def instance_actor_page?
34+
path_params[:controller] == 'instance_actors'
35+
end
36+
3137
def account_show_page?
3238
path_params[:controller] == 'accounts' && path_params[:action] == 'show'
3339
end

app/models/account.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class Account < ApplicationRecord
7878
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
7979

8080
# Local user validations
81-
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 128 }, if: -> { local? && will_save_change_to_username? }
81+
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 128 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
8282
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
8383
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
8484
validates :display_name, length: { maximum: 128 }, if: -> { local? && will_save_change_to_display_name? }
@@ -140,6 +140,10 @@ def bot?
140140
%w(Application Service).include? actor_type
141141
end
142142

143+
def instance_actor?
144+
id == -99
145+
end
146+
143147
alias bot bot?
144148

145149
def bot=(val)
@@ -499,7 +503,7 @@ def prepare_username
499503
end
500504

501505
def generate_keys
502-
return unless local? && !Rails.env.test?
506+
return unless local? && private_key.blank? && public_key.blank?
503507

504508
keypair = OpenSSL::PKey::RSA.new(2048)
505509
self.private_key = keypair.to_pem

app/models/concerns/account_finder_concern.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def find_remote!(username, domain)
1313
end
1414

1515
def representative
16-
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first
16+
Account.find(-99)
1717
end
1818

1919
def find_local(username)

0 commit comments

Comments
 (0)