Add instance info support
This commit is contained in:
parent
54f63a4be2
commit
d29b71bfd9
13 changed files with 181 additions and 16 deletions
|
@ -88,15 +88,18 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_params
|
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)
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
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)
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_domain_block_batch_params
|
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])
|
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])
|
||||||
end
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
|
|
|
@ -69,7 +69,8 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def domain_block_params
|
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)
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -101,6 +102,7 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_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)
|
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)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -507,7 +507,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
SCAN_SEARCHABILITY_FEDIBIRD_RE = /searchable_by_(all_users|followers_only|reacted_users_only|nobody)/
|
SCAN_SEARCHABILITY_FEDIBIRD_RE = /searchable_by_(all_users|followers_only|reacted_users_only|nobody)/
|
||||||
|
|
||||||
def searchability
|
def searchability
|
||||||
searchability_from_audience || searchability_from_bio || (marked_as_misskey_searchability? ? misskey_searchability : nil)
|
searchability_from_audience || searchability_from_bio || (misskey_software? ? misskey_searchability : nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def searchability_from_bio
|
def searchability_from_bio
|
||||||
|
@ -528,8 +528,15 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
searchability
|
searchability
|
||||||
end
|
end
|
||||||
|
|
||||||
def marked_as_misskey_searchability?
|
def instance_info
|
||||||
@marked_as_misskey_searchability ||= DomainBlock.detect_invalid_subscription?(@account.domain)
|
@instance_info ||= InstanceInfo.find_by(@account.domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def misskey_software?
|
||||||
|
info = instance_info
|
||||||
|
return DomainBlock.detect_invalid_subscription?(@account.domain) if info.nil?
|
||||||
|
|
||||||
|
%w(misskey calckey firefish).include?(info.software) || DomainBlock.detect_invalid_subscription?(@account.domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def misskey_searchability
|
def misskey_searchability
|
||||||
|
|
|
@ -153,9 +153,10 @@ class StatusReachFinder
|
||||||
end
|
end
|
||||||
|
|
||||||
def banned_domains_for_misskey_of_status(status)
|
def banned_domains_for_misskey_of_status(status)
|
||||||
blocks = DomainBlock.where(domain: nil)
|
return [] unless (status.public_unlisted_visibility? && status.account.user&.setting_reject_public_unlisted_subscription) || (status.unlisted_visibility? && status.account.user&.setting_reject_unlisted_subscription)
|
||||||
blocks = blocks.or(DomainBlock.where(detect_invalid_subscription: true)) if status.public_unlisted_visibility? && status.account.user&.setting_reject_public_unlisted_subscription
|
|
||||||
blocks = blocks.or(DomainBlock.where(detect_invalid_subscription: true)) if status.unlisted_visibility? && status.account.user&.setting_reject_unlisted_subscription
|
from_info = InstanceInfo.where(software: %w(misskey calckey firefish)).pluck(:domain)
|
||||||
blocks.pluck(:domain).uniq
|
from_domain_block = DomainBlock.where(detect_invalid_subscription: true).pluck(:domain)
|
||||||
|
(from_info + from_domain_block).uniq
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ class Instance < ApplicationRecord
|
||||||
belongs_to :domain_block
|
belongs_to :domain_block
|
||||||
belongs_to :domain_allow
|
belongs_to :domain_allow
|
||||||
belongs_to :unavailable_domain # skipcq: RB-RL1031
|
belongs_to :unavailable_domain # skipcq: RB-RL1031
|
||||||
|
belongs_to :instance_info
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :searchable, -> { where.not(domain: DomainBlock.select(:domain)) }
|
scope :searchable, -> { where.not(domain: DomainBlock.select(:domain)) }
|
||||||
|
|
17
app/models/instance_info.rb
Normal file
17
app/models/instance_info.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: instance_infos
|
||||||
|
#
|
||||||
|
# id :bigint(8) not null, primary key
|
||||||
|
# domain :string default(""), not null
|
||||||
|
# software :string default(""), not null
|
||||||
|
# version :string default(""), not null
|
||||||
|
# data :jsonb not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
|
||||||
|
class InstanceInfo < ApplicationRecord
|
||||||
|
end
|
|
@ -46,6 +46,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
create_account
|
create_account
|
||||||
|
fetch_instance_info
|
||||||
end
|
end
|
||||||
|
|
||||||
update_account
|
update_account
|
||||||
|
@ -207,6 +208,10 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
AccountMergingWorker.perform_async(@account.id)
|
AccountMergingWorker.perform_async(@account.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_instance_info
|
||||||
|
FetchInstanceInfoWorker.perform_async(@account.domain) unless InstanceInfo.exists?(domain: @account.domain)
|
||||||
|
end
|
||||||
|
|
||||||
def actor_type
|
def actor_type
|
||||||
if @json['type'].is_a?(Array)
|
if @json['type'].is_a?(Array)
|
||||||
@json['type'].find { |type| ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES.include?(type) }
|
@json['type'].find { |type| ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES.include?(type) }
|
||||||
|
@ -258,7 +263,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
bio = searchability_from_bio
|
bio = searchability_from_bio
|
||||||
return bio unless bio.nil?
|
return bio unless bio.nil?
|
||||||
|
|
||||||
return marked_as_misskey_searchability? ? :public : :private
|
return misskey_software? ? :public : :private
|
||||||
end
|
end
|
||||||
|
|
||||||
if audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) }
|
if audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) }
|
||||||
|
@ -288,8 +293,15 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
searchability
|
searchability
|
||||||
end
|
end
|
||||||
|
|
||||||
def marked_as_misskey_searchability?
|
def instance_info
|
||||||
domain_block&.detect_invalid_subscription
|
@instance_info ||= InstanceInfo.find_by(@domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def misskey_software?
|
||||||
|
info = instance_info
|
||||||
|
return domain_block&.detect_invalid_subscription if info.nil?
|
||||||
|
|
||||||
|
%w(misskey calckey firefish).include?(info.software) || domain_block&.detect_invalid_subscription
|
||||||
end
|
end
|
||||||
|
|
||||||
def subscribable_by
|
def subscribable_by
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
- content_for :page_title do
|
- content_for :page_title do
|
||||||
= @instance.domain
|
= @instance.domain
|
||||||
|
|
||||||
|
-if @instance.instance_info.present?
|
||||||
|
%p
|
||||||
|
= "#{@instance.instance_info.software} #{@instance.instance_info.version}"
|
||||||
|
|
||||||
- content_for :header_tags do
|
- content_for :header_tags do
|
||||||
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
|
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
|
||||||
|
|
||||||
|
|
75
app/workers/fetch_instance_info_worker.rb
Normal file
75
app/workers/fetch_instance_info_worker.rb
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class FetchInstanceInfoWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
include JsonLdHelper
|
||||||
|
include Redisable
|
||||||
|
include Lockable
|
||||||
|
|
||||||
|
class Error < StandardError; end
|
||||||
|
class GoneError < Error; end
|
||||||
|
class RequestError < Error; end
|
||||||
|
|
||||||
|
def perform(domain)
|
||||||
|
@instance = Instance.find_by(domain: domain)
|
||||||
|
return if !@instance || @instance.unavailable_domain.present?
|
||||||
|
|
||||||
|
with_redis_lock("instance_info:#{domain}") do
|
||||||
|
link = nodeinfo_link
|
||||||
|
return if link.nil?
|
||||||
|
|
||||||
|
update_info!(link)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def nodeinfo_link
|
||||||
|
nodeinfo = fetch_json("https://#{@instance.domain}/.well-known/nodeinfo")
|
||||||
|
return nil if nodeinfo.nil? || !nodeinfo.key?('links')
|
||||||
|
|
||||||
|
nodeinfo_links = nodeinfo['links']
|
||||||
|
return nil if !nodeinfo_links.is_a?(Array) || nodeinfo_links.blank?
|
||||||
|
|
||||||
|
nodeinfo_link = nodeinfo_links.find { |item| item.key?('rel') && item.key?('href') && item['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0' }
|
||||||
|
return nil if nodeinfo_link.nil? || nodeinfo_link['href'].nil? || !nodeinfo_link['href'].start_with?('http')
|
||||||
|
|
||||||
|
nodeinfo_link['href']
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_info!(url)
|
||||||
|
content = fetch_json(url)
|
||||||
|
return nil if content.nil? || !content.key?('software') || !content['software'].key?('name')
|
||||||
|
|
||||||
|
software = content['software']['name']
|
||||||
|
version = content['software'].key?('version') ? content['software']['version'] : ''
|
||||||
|
|
||||||
|
exists = @instance.instance_info
|
||||||
|
if exists.nil?
|
||||||
|
InstanceInfo.create!(domain: @instance.domain, software: software, version: version, data: content)
|
||||||
|
else
|
||||||
|
exists.software = software
|
||||||
|
exists.version = version
|
||||||
|
exists.data = content
|
||||||
|
exists.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_json(url)
|
||||||
|
build_request(url).perform do |response|
|
||||||
|
if [200, 203].include?(response.code)
|
||||||
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||||
|
|
||||||
|
body_to_json(response.body_with_limit)
|
||||||
|
elsif response.code == 410
|
||||||
|
raise FetchInstanceInfoWorker::GoneError, "#{domain} is gone from the server"
|
||||||
|
else
|
||||||
|
raise FetchInstanceInfoWorker::RequestError, "Request for #{domain} returned HTTP #{response.code}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_request(url)
|
||||||
|
Request.new(:get, url).add_headers('Accept' => 'application/jrd+json, application/json')
|
||||||
|
end
|
||||||
|
end
|
15
app/workers/scheduler/update_instance_info_scheduler.rb
Normal file
15
app/workers/scheduler/update_instance_info_scheduler.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Scheduler::UpdateInstanceInfoScheduler
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
sidekiq_options retry: 1
|
||||||
|
|
||||||
|
def perform
|
||||||
|
Instance.select(:domain).reorder(nil).find_in_batches do |instances|
|
||||||
|
FetchInstanceInfoWorker.push_bulk(instances) do |instance|
|
||||||
|
[instance.domain]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -62,3 +62,7 @@
|
||||||
interval: 30 seconds
|
interval: 30 seconds
|
||||||
class: Scheduler::SidekiqHealthScheduler
|
class: Scheduler::SidekiqHealthScheduler
|
||||||
queue: scheduler
|
queue: scheduler
|
||||||
|
update_instance_info_scheduler:
|
||||||
|
cron: '0 0 * * *'
|
||||||
|
class: Scheduler::UpdateInstanceInfoScheduler
|
||||||
|
queue: scheduler
|
||||||
|
|
14
db/migrate/20230804222017_create_instance_infoes.rb
Normal file
14
db/migrate/20230804222017_create_instance_infoes.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateInstanceInfoes < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
create_table :instance_infos do |t|
|
||||||
|
t.string :domain, null: false, default: '', index: { unique: true }
|
||||||
|
t.string :software, null: false, default: ''
|
||||||
|
t.string :version, null: false, default: ''
|
||||||
|
t.jsonb :data, null: false, default: {}
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.datetime :updated_at, null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
12
db/schema.rb
12
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.0].define(version: 2023_07_24_160715) do
|
ActiveRecord::Schema[7.0].define(version: 2023_08_04_222017) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
@ -631,6 +631,16 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_24_160715) do
|
||||||
t.boolean "overwrite", default: false, null: false
|
t.boolean "overwrite", default: false, null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "instance_infos", force: :cascade do |t|
|
||||||
|
t.string "domain", default: "", null: false
|
||||||
|
t.string "software", default: "", null: false
|
||||||
|
t.string "version", default: "", null: false
|
||||||
|
t.jsonb "data", default: {}, null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["domain"], name: "index_instance_infos_on_domain", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "invites", force: :cascade do |t|
|
create_table "invites", force: :cascade do |t|
|
||||||
t.bigint "user_id", null: false
|
t.bigint "user_id", null: false
|
||||||
t.string "code", default: "", null: false
|
t.string "code", default: "", null: false
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue