fedipub-moderation 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1ce4eb580ac4093a39a006480b07f863e6b2f4ae8bb1d077a42ecc10799c7f55
4
+ data.tar.gz: d94937b13d7a3a1f730ed89a790b2647a03b4dcc8e7aed060d4231b0fd529361
5
+ SHA512:
6
+ metadata.gz: 3cd1c951cf24d4c47c914440f014703f416058fc8cce885b284256b9f0e05b04891758a61779eb6cd55a2d75ce5c405e1cfadd3c07d0b36fd7220fdce2c11ff5
7
+ data.tar.gz: 6dc30a28a28d2b27e6ab15de37e52204cb2b2e9f7e220ea7dde7b87965db16cb7d2e17260ab1ad4fde375892a1a167fca57c7d4a5dbfa0058361d9beb84dbd88
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Fedipub::Moderation
2
+
3
+ ![Gitlab Build Status](https://img.shields.io/gitlab/pipeline-status/fedipub%2Ffedipub-moderation)
4
+ ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/rubygems/fedipub-moderation)
5
+
6
+ ![Gem Version](https://img.shields.io/gem/v/fedipub-moderation)
7
+ ![Gem Downloads (for latest version)](https://img.shields.io/gem/dtv/fedipub-moderation)
8
+ ![Dependent repos (via libraries.io)](https://img.shields.io/librariesio/dependent-repos/rubygems/fedipub-moderation)
9
+
10
+ A gem that provides moderation capabilities for [Fedipub](https://gitlab.com/fedipub/fedipub). It adds the following features:
11
+
12
+ * Handle incoming `Flag` activities, normally used for reporting content to moderators
13
+ * Block federation with particular servers
14
+
15
+ [!note]
16
+ This gem was previously called `federails-moderation`, but has changed name in line with the rename of Federails to Fedipub.
17
+
18
+ ## Requirements
19
+
20
+ * [Fedipub](https://gitlab.com/fedipub/fedipub) >= 0.8
21
+ * Ruby >= 3.0
22
+
23
+ ## Installation
24
+ Add the gem to your Rails application:
25
+
26
+ ```bash
27
+ > bundle add "fedipub-moderation"
28
+ ```
29
+
30
+ Then install the database migrations:
31
+
32
+ ```bash
33
+ > bin/rails fedipub_moderation:install:migrations
34
+ > bin/rails db:migrate
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Reports
40
+
41
+ When your application receives a `Flag` activitypub message, it will create a `Fedipub::Moderation::Report` record with the details.
42
+
43
+ ```ruby
44
+ # Find all unresolved reports
45
+ reports = Fedipub::Moderation::Report.where(resolution: nil)
46
+ r = reports.first
47
+
48
+ # Reports can have a comment that was sent with them:
49
+ puts r.content
50
+ # "This message is spam"
51
+
52
+ # It will be associated with the actor that sent it:
53
+ puts r.actor.at_address
54
+ # "@floppy@mastodon.me.uk"
55
+
56
+ # Deal with the report in your app, then either:
57
+ r.resolve!
58
+ # or, you can ignore it
59
+ r.ignore!
60
+
61
+ ```
62
+
63
+ You can receive a callback in your application when a new report is received, by providing a proc which will be called:
64
+
65
+ ```
66
+ Fedipub::Moderation.configure do |conf|
67
+ conf.after_report_created = ->(report) { MyApp::MyReportHandler.call(report) }
68
+ end
69
+ ```
70
+
71
+ ### Domain Blocks
72
+
73
+ You can block domains that are abusive like so:
74
+
75
+ ```
76
+ Fedipub::Moderation::DomainBlock.create(domain: "spammer.com")
77
+ ```
78
+
79
+ Once the block is created, incoming messages from that domain, or from any actor on that domain, will be ignored. Also, outgoing messages to that domain will be dropped before being delivered.
80
+
81
+ Actors from the blocked domain aren't currently auto-removed; this may be added in the future, but for now that's left up to your application.
82
+
83
+ ## Contributing
84
+
85
+ Bug reports and pull requests are welcome on GitLab at https://gitlab.com/fedipub/fedipub-moderation. This project is intended to be a safe, welcoming space for collaboration; everyone interacting in the project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/fedipub/fedipub-moderation/-/blob/main/CODE_OF_CONDUCT.md).
86
+
87
+ ## Support & Community
88
+
89
+ For help, join the main [Fedipub matrix chat room](https://matrix.to/#/#fedipub:matrix.org).
90
+
91
+ ## Acknowledgements
92
+
93
+ This gem builds on top of [Fedipub](https://gitlab.com/fedipub/fedipub), by [Manuel Tancoigne](https://gitlab.com/mtancoigne).
94
+
95
+ This gem was initially created as part of [Manyfold](https://manyfold.app), with funding from [NGI0 Entrust](https://nlnet.nl/entrust), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program.
96
+
97
+ [<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
98
+ [<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/entrust)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1,12 @@
1
+ module Fedipub::Moderation
2
+ class DomainBlock < ApplicationRecord
3
+ validates :domain, presence: true, uniqueness: true, "fedipub/moderation/domain_name": true
4
+
5
+ def self.blocked?(query)
6
+ self.exists?(domain: [ query, PublicSuffix.parse(query).domain ])
7
+ rescue PublicSuffix::Error
8
+ # Allow things that we don't understand
9
+ false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ class Fedipub::Moderation::Report < ApplicationRecord
2
+ belongs_to :fedipub_actor, class_name: "Fedipub::Actor", optional: true
3
+ belongs_to :object, polymorphic: true, optional: true
4
+
5
+ after_create :execute_create_callback
6
+
7
+ def resolve!
8
+ update!(resolved_at: DateTime.now, resolution: "resolved")
9
+ end
10
+
11
+ def ignore!
12
+ update!(resolved_at: DateTime.now, resolution: "ignored")
13
+ end
14
+
15
+ def reporter_address
16
+ if fedipub_actor
17
+ fedipub_actor.at_address
18
+ else
19
+ URI.parse(federated_url).host
20
+ end
21
+ end
22
+
23
+ def local?
24
+ fedipub_actor&.local?
25
+ end
26
+
27
+ private
28
+
29
+ def execute_create_callback
30
+ Fedipub::Moderation::Configuration.after_report_created&.call self
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module Fedipub::Moderation
2
+ class ApplicationService
3
+ def self.call(*args, &block)
4
+ new(*args, &block).call
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ module Fedipub::Moderation
2
+ class ReportCreationService < ApplicationService
3
+ def initialize(activity)
4
+ @activity = activity
5
+ Rails.logger.info "Report recieved: #{@activity.inspect}"
6
+ end
7
+
8
+ def call
9
+ Report.create!(
10
+ fedipub_actor: find_reporter,
11
+ object: find_objects.first,
12
+ federated_url: @activity["id"],
13
+ content: @activity["content"]
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def find_reporter
20
+ Fedipub::Actor.find_or_create_by_federation_url(@activity["actor"])
21
+ rescue ActiveRecord::RecordInvalid, URI::InvalidURIError
22
+ # Anonymous reports will try to create invalid actors, so we end up here
23
+ nil
24
+ end
25
+
26
+ def find_objects
27
+ objects = Array(@activity["object"]).map { |url|
28
+ begin
29
+ # Find reported actors
30
+ Fedipub::Actor.find_by_federation_url(url)
31
+ # Other objects could be here too, but they will come later
32
+ rescue ActiveRecord::RecordNotFound
33
+ nil
34
+ end
35
+ }.compact
36
+ Rails.logger.warn "Fedipub::Moderation cannot currently handle multiple objects in a single report, only the first has been logged" if objects.length > 1
37
+ objects
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ require "public_suffix"
2
+
3
+ module Fedipub::Moderation
4
+ class DomainNameValidator < ActiveModel::EachValidator
5
+ def validate_each(record, attribute, value)
6
+ record.errors.add attribute, :invalid unless PublicSuffix.valid?(value, default_rule: nil)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require "fediverse/inbox"
2
+ require "fedipub/moderation/filtered_inbox"
3
+
4
+ Fediverse::Inbox.send(:include, Fedipub::Moderation::FilteredInbox)
5
+
6
+ require "fediverse/notifier"
7
+ require "fedipub/moderation/filtered_notifier"
8
+
9
+ Fediverse::Notifier.send(:include, Fedipub::Moderation::FilteredNotifier)
@@ -0,0 +1,5 @@
1
+ require "fediverse/inbox"
2
+
3
+ Rails.application.config.after_initialize do
4
+ Fediverse::Inbox.register_handler "Flag", "*", Fedipub::Moderation::ReportCreationService, :call
5
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,13 @@
1
+ class CreateFederailsModerationReports < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :federails_moderation_reports do |t|
4
+ t.string :federated_url
5
+ t.references :federails_actor, foreign_key: true
6
+ t.string :content
7
+ t.references :object, polymorphic: true
8
+ t.datetime :resolved_at
9
+ t.string :resolution
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ class CreateFederailsModerationDomainBlocks < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :federails_moderation_domain_blocks do |t|
4
+ t.string "domain", null: false, index: { unique: true }
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class RenameFederailsModerationToFedipubModeration < ActiveRecord::Migration[7.2]
2
+ def change
3
+ rename_column :federails_moderation_reports, :federails_actor_id, :fedipub_actor_id
4
+ rename_index :federails_moderation_reports, "index_federails_moderation_reports_on_object", "index_fedipub_moderation_reports_on_object"
5
+ rename_table :federails_moderation_reports, :fedipub_moderation_reports
6
+ rename_table :federails_moderation_domain_blocks, :fedipub_moderation_domain_blocks
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ module Fedipub::Moderation
2
+ # rubocop:disable Style/ClassVars
3
+
4
+ # Stores the Fedipub::Moderation configuration in a _singleton_.
5
+ module Configuration
6
+ # A proc that is called any time new report is created
7
+ # Useful for sending notifications
8
+ mattr_accessor :after_report_created
9
+ end
10
+ # rubocop:enable Style/ClassVars
11
+ end
@@ -0,0 +1,9 @@
1
+ require "fedipub"
2
+
3
+ module Fedipub
4
+ module Moderation
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Fedipub::Moderation
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Fedipub::Moderation
2
+ module FilteredInbox
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class <<self
7
+ def filter_request(payload)
8
+ filtered_dispatch_request(payload) unless
9
+ (payload["id"] && DomainBlock.blocked?(URI.parse(payload["id"]).host)) ||
10
+ (payload["actor"] && DomainBlock.blocked?(URI.parse(payload["actor"]).host))
11
+ end
12
+
13
+ alias_method :filtered_dispatch_request, :dispatch_request
14
+ alias_method :dispatch_request, :filter_request
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module Fedipub::Moderation
2
+ module FilteredNotifier
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class <<self
7
+ def filter_post_to_inbox(inbox_url:, message:, from: nil)
8
+ filtered_post_to_inbox(inbox_url: inbox_url, message: message, from: from) unless DomainBlock.blocked?(URI.parse(inbox_url).hostname)
9
+ end
10
+
11
+ alias_method :filtered_post_to_inbox, :post_to_inbox
12
+ alias_method :post_to_inbox, :filter_post_to_inbox
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ module Fedipub
2
+ module Moderation
3
+ class Railtie < ::Rails::Railtie
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Fedipub
2
+ module Moderation
3
+ VERSION = "0.5.0"
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ require "fedipub/moderation/version"
2
+ require "fedipub/moderation/engine"
3
+ require "fedipub/moderation/configuration"
4
+
5
+ module Fedipub
6
+ module Moderation
7
+ mattr_reader :configuration
8
+ @@configuration = Configuration
9
+
10
+ def self.configure
11
+ yield @@configuration
12
+ end
13
+
14
+ def self.table_name_prefix
15
+ "fedipub_moderation_"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :fedipub_moderation do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fedipub-moderation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - James Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.2.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.2.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: fedipub
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: public_suffix
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '6'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '8'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '6'
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '8'
61
+ - !ruby/object:Gem::Dependency
62
+ name: simplecov
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.22'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.22'
75
+ description: Moderation additions for Fedipub; reporting, limit/suspend, server blocking,
76
+ etc
77
+ email:
78
+ - james@floppy.org.uk
79
+ executables: []
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - README.md
84
+ - Rakefile
85
+ - app/models/fedipub/moderation/domain_block.rb
86
+ - app/models/fedipub/moderation/report.rb
87
+ - app/services/fedipub/moderation/application_service.rb
88
+ - app/services/fedipub/moderation/report_creation_service.rb
89
+ - app/validators/fedipub/moderation/domain_name_validator.rb
90
+ - config/initializers/extensions.rb
91
+ - config/initializers/handlers.rb
92
+ - config/routes.rb
93
+ - db/migrate/20241127105043_create_federails_moderation_reports.rb
94
+ - db/migrate/20241128115659_create_federails_moderation_domain_blocks.rb
95
+ - db/migrate/20260729204941_rename_federails_moderation_to_fedipub_moderation.rb
96
+ - lib/fedipub/moderation.rb
97
+ - lib/fedipub/moderation/configuration.rb
98
+ - lib/fedipub/moderation/engine.rb
99
+ - lib/fedipub/moderation/filtered_inbox.rb
100
+ - lib/fedipub/moderation/filtered_notifier.rb
101
+ - lib/fedipub/moderation/railtie.rb
102
+ - lib/fedipub/moderation/version.rb
103
+ - lib/tasks/fedipub/moderation_tasks.rake
104
+ homepage: https://gitlab.com/fedipub/fedipub-moderation
105
+ licenses:
106
+ - MIT
107
+ metadata:
108
+ homepage_uri: https://gitlab.com/fedipub/fedipub-moderation
109
+ source_code_uri: https://gitlab.com/fedipub/fedipub-moderation
110
+ changelog_uri: https://gitlab.com/fedipub/fedipub-moderation/releases
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '3.3'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubygems_version: 3.5.22
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Moderation additions for Fedipub.
130
+ test_files: []