diff --git a/.github/test-env-configs.json b/.github/test-env-configs.json
index 88d25f8..09ce17b 100644
--- a/.github/test-env-configs.json
+++ b/.github/test-env-configs.json
@@ -12,7 +12,8 @@
"DISABLE_POKECODE_FOOTER": "",
"DISABLE_LANGUAGE_MENU": "",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "",
- "ALLOWED_RECIPIENTS": ""
+ "ALLOWED_RECIPIENTS": "",
+ "DISABLE_INVITATIONS": ""
},
{
"env-config": "all-disabled",
@@ -27,7 +28,8 @@
"DISABLE_POKECODE_FOOTER": "1",
"DISABLE_LANGUAGE_MENU": "1",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "1",
- "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com"
+ "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com",
+ "DISABLE_INVITATIONS": "true"
},
{
"env-config": "footer-only",
@@ -42,7 +44,8 @@
"DISABLE_POKECODE_FOOTER": "",
"DISABLE_LANGUAGE_MENU": "1",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "1",
- "ALLOWED_RECIPIENTS": ""
+ "ALLOWED_RECIPIENTS": "",
+ "DISABLE_INVITATIONS": ""
},
{
"env-config": "language-menu-only",
@@ -57,7 +60,8 @@
"DISABLE_POKECODE_FOOTER": "1",
"DISABLE_LANGUAGE_MENU": "",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "1",
- "ALLOWED_RECIPIENTS": ""
+ "ALLOWED_RECIPIENTS": "",
+ "DISABLE_INVITATIONS": ""
},
{
"env-config": "assembly-members-visible-only",
@@ -72,7 +76,8 @@
"DISABLE_POKECODE_FOOTER": "1",
"DISABLE_LANGUAGE_MENU": "1",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "",
- "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com"
+ "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com",
+ "DISABLE_INVITATIONS": ""
},
{
"env-config": "admin-iframe-only",
@@ -87,6 +92,7 @@
"DISABLE_POKECODE_FOOTER": "1",
"DISABLE_LANGUAGE_MENU": "1",
"DISABLE_ASSEMBLY_MEMBERS_VISIBLE": "1",
- "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com"
+ "ALLOWED_RECIPIENTS": "recipient1@example.com recipient2@example.com",
+ "DISABLE_INVITATIONS": ""
}
]
diff --git a/README.md b/README.md
index df4c2b2..b764e4b 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ This plugin relies on the command `decidim:upgrade` to make sure common files ar
| `AWS_FORCE_PATH_STYLE` | Certain providers do not support the bucket name as the subdomain of the AWS endpoint (ie: Contabo). Set to `true` if that's the case. | `false` | |
| `CONTENT_SECURITY_POLICY` | Sets custom Content Security Policy headers for enhanced security. When set, it is added to the default CSP configuration. | `""` (disabled) | |
| `ALLOWED_RECIPIENTS` | A list of emails or domains that must match in order to send an email, separated by spaces. For instance `@pokecode.net johnsmith@gmail.com`. Exact email addresses (without a leading `@`) must match the full recipient email, while domain patterns starting with `@` are matched as suffixes of the recipient email. Leave empty to disable any interception. | `""` |
+| `DISABLE_INVITATIONS` | Prevents all invitation emails from being sent by intercepting emails with the `invitation-instructions` header. This is useful for development or testing environments. | `false` | |
## Installation
diff --git a/lib/decidim/pokecode/mail_interceptor.rb b/app/mailers/decidim/pokecode/allowed_recipients_mail_interceptor.rb
similarity index 98%
rename from lib/decidim/pokecode/mail_interceptor.rb
rename to app/mailers/decidim/pokecode/allowed_recipients_mail_interceptor.rb
index 06268a7..7c370a6 100644
--- a/lib/decidim/pokecode/mail_interceptor.rb
+++ b/app/mailers/decidim/pokecode/allowed_recipients_mail_interceptor.rb
@@ -4,7 +4,7 @@ module Decidim
module Pokecode
# Email interceptor that filters outgoing emails based on allowed recipients.
# Only allows emails to recipients that match the configured allowed list.
- class MailInterceptor
+ class AllowedRecipientsMailInterceptor
def self.delivering_email(message)
return if allowed_recipients_empty?
diff --git a/app/mailers/decidim/pokecode/disable_invitations_mail_interceptor.rb b/app/mailers/decidim/pokecode/disable_invitations_mail_interceptor.rb
new file mode 100644
index 0000000..58255ac
--- /dev/null
+++ b/app/mailers/decidim/pokecode/disable_invitations_mail_interceptor.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Decidim
+ module Pokecode
+ # Email interceptor that prevents invitation emails from being sent.
+ # Disables all emails that contain the 'invitation-instructions' header.
+ class DisableInvitationsMailInterceptor
+ def self.delivering_email(message)
+ return unless Decidim::Pokecode.disable_invitations
+
+ # Check if this is an invitation email
+ if message["invitation-instructions"].present?
+ Rails.logger.info "[Decidim::Pokecode] Invitation email prevented. Instructions: #{message["invitation-instructions"]}, To: #{message.to.join(", ")}"
+ message.perform_deliveries = false
+ end
+ end
+ end
+ end
+end
diff --git a/app/overrides/decidim/add_staging_warning.rb b/app/overrides/decidim/add_staging_warning.rb
deleted file mode 100644
index 07a241e..0000000
--- a/app/overrides/decidim/add_staging_warning.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-if Decidim::Pokecode.allowed_recipients_list.any?
- Deface::Override.new(:virtual_path => "decidim/admin/dashboard/show",
- :name => "add-staging-warning",
- :insert_before => "div.content",
- :partial => "decidim/pokecode/staging_warning")
-end
diff --git a/app/views/decidim/pokecode/admin/_invitations_disabled_warning.html.erb b/app/views/decidim/pokecode/admin/_invitations_disabled_warning.html.erb
new file mode 100644
index 0000000..9001d9b
--- /dev/null
+++ b/app/views/decidim/pokecode/admin/_invitations_disabled_warning.html.erb
@@ -0,0 +1,6 @@
+
+
+ <%= t("decidim.pokecode.invitations_disabled_warning.title") %>
+ <%= t("decidim.pokecode.invitations_disabled_warning.message") %>
+
+
diff --git a/app/views/decidim/pokecode/_staging_warning.html.erb b/app/views/decidim/pokecode/admin/_staging_warning.html.erb
similarity index 100%
rename from app/views/decidim/pokecode/_staging_warning.html.erb
rename to app/views/decidim/pokecode/admin/_staging_warning.html.erb
diff --git a/config/locales/en.yml b/config/locales/en.yml
index f893e0e..9f9e06c 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -5,3 +5,6 @@ en:
staging_warning:
title: "Warning: Staging Environment"
message: "Emails sent from this instance may not reach their intended recipients. Allowed destinations are: %{emails}."
+ invitations_disabled_warning:
+ title: "Warning: Invitations Disabled"
+ message: "Invitation emails are currently disabled in this instance. Users will not receive invitation emails."
diff --git a/lib/decidim/pokecode.rb b/lib/decidim/pokecode.rb
index 4e96e76..7f2338f 100644
--- a/lib/decidim/pokecode.rb
+++ b/lib/decidim/pokecode.rb
@@ -3,9 +3,9 @@
require "decidim/pokecode/configuration"
require "rails"
require "decidim/core"
+require "deface"
require "health_check" if Decidim::Pokecode.health_check_enabled
require "rails_semantic_logger" if Decidim::Pokecode.semantic_logger_enabled
-require "deface" if Decidim::Pokecode.deface_enabled
require "aws-sdk-s3" if Decidim::Pokecode.aws_cdn_host.present?
require "decidim/pokecode/s3_object_override" if Decidim::Pokecode.aws_cdn_host.present?
@@ -19,8 +19,6 @@
require "sidekiq/cron"
end
-require "decidim/pokecode/mail_interceptor" if Decidim::Pokecode.allowed_recipients_list.any?
-
require "decidim/pokecode/admin"
require "decidim/pokecode/engine"
require "decidim/pokecode/admin_engine"
diff --git a/lib/decidim/pokecode/configuration.rb b/lib/decidim/pokecode/configuration.rb
index a120730..6a22394 100644
--- a/lib/decidim/pokecode/configuration.rb
+++ b/lib/decidim/pokecode/configuration.rb
@@ -69,6 +69,10 @@ module Pokecode
Decidim::Env.new("ALLOWED_RECIPIENTS", "").value
end
+ config_accessor :disable_invitations do
+ Decidim::Env.new("DISABLE_INVITATIONS", false).present?
+ end
+
config_accessor :content_security_policies_extra do
{
"connect-src" => ENV.fetch("CONTENT_SECURITY_POLICY", "").split,
@@ -94,10 +98,6 @@ def self.allowed_recipients_list
Pokecode.allowed_recipients&.split(/[,\s]+/)&.reject(&:blank?) || []
end
- def self.deface_enabled
- Pokecode.pokecode_footer_enabled || Decidim::Pokecode.language_menu_enabled
- end
-
def self.sentry_enabled
Pokecode.sentry_dsn.present?
end
diff --git a/lib/decidim/pokecode/engine.rb b/lib/decidim/pokecode/engine.rb
index 59d9aad..fc45a54 100644
--- a/lib/decidim/pokecode/engine.rb
+++ b/lib/decidim/pokecode/engine.rb
@@ -75,6 +75,23 @@ class Engine < ::Rails::Engine
else
Rails.logger.info "[Decidim::Pokecode] Active Storage CDN override disabled."
end
+
+ # Register deface overrides for admin dashboard warnings
+ if Decidim::Pokecode.allowed_recipients_list.any?
+ Deface::Override.new(:virtual_path => "decidim/admin/dashboard/show",
+ :name => "add-staging-warning",
+ :insert_before => "div.content",
+ :partial => "decidim/pokecode/admin/staging_warning")
+ Rails.logger.info "[Decidim::Pokecode] Staging warning deface override registered."
+ end
+
+ if Decidim::Pokecode.disable_invitations
+ Deface::Override.new(:virtual_path => "decidim/admin/dashboard/show",
+ :name => "add-invitations-disabled-warning",
+ :insert_before => "div.content",
+ :partial => "decidim/pokecode/admin/invitations_disabled_warning")
+ Rails.logger.info "[Decidim::Pokecode] Invitations disabled warning deface override registered."
+ end
end
initializer "pokecode.zeitwerk_ignore_deface" do
@@ -176,12 +193,24 @@ class Engine < ::Rails::Engine
end
initializer "pokecode.mail_interceptor" do
- if Decidim::Pokecode.allowed_recipients_list.any?
- config.action_mailer.interceptors ||= []
- config.action_mailer.interceptors << "Decidim::Pokecode::MailInterceptor"
- Rails.logger.info "[Decidim::Pokecode] Email interceptor enabled. Allowed recipients: #{Decidim::Pokecode.allowed_recipients_list.join(", ")}"
- else
- Rails.logger.info "[Decidim::Pokecode] Email interceptor disabled."
+ Rails.application.config.to_prepare do
+ if Decidim::Pokecode.allowed_recipients_list.any?
+ unless ActionMailer::Base.try(:delivery_interceptors)&.include?(Decidim::Pokecode::AllowedRecipientsMailInterceptor)
+ ActionMailer::Base.register_interceptor(Decidim::Pokecode::AllowedRecipientsMailInterceptor)
+ end
+ Rails.logger.info "[Decidim::Pokecode] Allowed recipients mail interceptor enabled. Allowed recipients: #{Decidim::Pokecode.allowed_recipients_list.join(", ")}"
+ else
+ Rails.logger.info "[Decidim::Pokecode] Allowed recipients mail interceptor disabled."
+ end
+
+ if Decidim::Pokecode.disable_invitations
+ unless ActionMailer::Base.try(:delivery_interceptors)&.include?(Decidim::Pokecode::DisableInvitationsMailInterceptor)
+ ActionMailer::Base.register_interceptor(Decidim::Pokecode::DisableInvitationsMailInterceptor)
+ end
+ Rails.logger.info "[Decidim::Pokecode] Invitations disabled via mail interceptor."
+ else
+ Rails.logger.info "[Decidim::Pokecode] Invitations not disabled via mail interceptor."
+ end
end
end
end
diff --git a/spec/lib/loaded_gems_spec.rb b/spec/lib/loaded_gems_spec.rb
index ea8e685..ee3927f 100644
--- a/spec/lib/loaded_gems_spec.rb
+++ b/spec/lib/loaded_gems_spec.rb
@@ -48,16 +48,6 @@ module Decidim
end
end
- if Decidim::Pokecode.deface_enabled
- it "loads Deface" do
- expect(defined?(Deface)).to be_truthy
- end
- else
- it "does not load Deface" do
- expect(defined?(Deface)).to be_falsey
- end
- end
-
if Decidim::Pokecode.aws_cdn_host.present?
it "loads Aws::S3" do
expect(Aws::S3::Object.included_modules).to include(Decidim::Pokecode::S3ObjectOverride)
diff --git a/spec/mailers/disable_invitations_mail_interceptor_spec.rb b/spec/mailers/disable_invitations_mail_interceptor_spec.rb
new file mode 100644
index 0000000..9e57a08
--- /dev/null
+++ b/spec/mailers/disable_invitations_mail_interceptor_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+module Decidim::Pokecode
+ describe DisableInvitationsMailInterceptor do
+ let(:message) do
+ instance_double(
+ Mail::Message,
+ to: ["user@example.com"],
+ perform_deliveries: true
+ )
+ end
+
+ before do
+ allow(Rails.logger).to receive(:info)
+ allow(message).to receive(:perform_deliveries=)
+ allow(message).to receive(:[]).and_return(nil)
+ end
+
+ describe ".delivering_email" do
+ context "when disable_invitations is disabled" do
+ before do
+ allow(Decidim::Pokecode).to receive(:disable_invitations).and_return(false)
+ end
+
+ it "does not intercept any emails" do
+ allow(message).to receive(:[]).with("invitation-instructions").and_return("invite_private_user")
+ described_class.delivering_email(message)
+ expect(message).not_to have_received(:perform_deliveries=)
+ end
+ end
+
+ context "when disable_invitations is enabled" do
+ before do
+ allow(Decidim::Pokecode).to receive(:disable_invitations).and_return(true)
+ end
+
+ context "when the email has an invitation-instructions header" do
+ before do
+ allow(message).to receive(:[]).with("invitation-instructions").and_return("invite_private_user")
+ end
+
+ it "prevents the email from being delivered" do
+ described_class.delivering_email(message)
+ expect(message).to have_received(:perform_deliveries=).with(false)
+ end
+
+ it "logs the interception" do
+ described_class.delivering_email(message)
+ expect(Rails.logger).to have_received(:info).with(
+ include("[Decidim::Pokecode] Invitation email prevented")
+ )
+ end
+ end
+
+ context "when the email does not have an invitation-instructions header" do
+ before do
+ allow(message).to receive(:[]).with("invitation-instructions").and_return(nil)
+ end
+
+ it "allows the email to be delivered" do
+ described_class.delivering_email(message)
+ expect(message).not_to have_received(:perform_deliveries=)
+ end
+
+ it "does not log the interception" do
+ described_class.delivering_email(message)
+ expect(Rails.logger).not_to have_received(:info)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/mailers/mail_interceptor_spec.rb b/spec/mailers/mail_interceptor_spec.rb
index 972c512..cdede98 100644
--- a/spec/mailers/mail_interceptor_spec.rb
+++ b/spec/mailers/mail_interceptor_spec.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
require "spec_helper"
-require "decidim/pokecode/mail_interceptor"
module Decidim::Pokecode
- describe MailInterceptor do
+ describe AllowedRecipientsMailInterceptor do
let(:message) do
instance_double(
Mail::Message,
diff --git a/spec/system/allowed_recipients_spec.rb b/spec/system/mail_interceptor_spec.rb
similarity index 58%
rename from spec/system/allowed_recipients_spec.rb
rename to spec/system/mail_interceptor_spec.rb
index 74256d4..3630412 100644
--- a/spec/system/allowed_recipients_spec.rb
+++ b/spec/system/mail_interceptor_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe "AllowedRecipients" do
+describe "MailInterceptor" do
let!(:organization) { create(:organization) }
let!(:user) { create(:user, :confirmed, :admin, organization:) }
@@ -24,4 +24,15 @@
expect(page).to have_no_content("Warning: Staging Environment")
end
end
+
+ if Decidim::Pokecode.disable_invitations
+ it "shows the invitations disabled warning in the admin dashboard" do
+ expect(page).to have_content("Warning: Invitations Disabled")
+ expect(page).to have_content("Invitation emails are currently disabled in this instance. Users will not receive invitation emails.")
+ end
+ else
+ it "does not show the invitations disabled warning in the admin dashboard" do
+ expect(page).to have_no_content("Warning: Invitations Disabled")
+ end
+ end
end