Commit 7c8bf724 authored by Mic Kaczmarczik's avatar Mic Kaczmarczik
Browse files

Feature: optionally restrict list ownership to addresses in specific domains (owner_domain)

parent dbaa9f95
......@@ -96,6 +96,11 @@ owner.info owner hidden
owner_include owner read
owner_domain owner read
owner_domain_min owner read
owner_domain privileged_owner write
owner_domain_min privileged_owner write
editor owner read
editor privileged_owner write
......
......@@ -799,6 +799,12 @@ Warning: this message may already have been sent by one of the list's editors.[%
[%~ ELSIF report_entry == 'merge_failed' ~%]
[%|loc(report_param.error)%]Your message cannot be personalized due to error: %1. Please check template syntax.[%END%]
[%~ ELSIF report_entry == 'owner_domain' ~%]
[%|loc(report_param.value,report_param.owner_domain)%]%1: all list owners must be in the following domains: %2.[%END%]
[%~ ELSIF report_entry == 'owner_domain_min' ~%]
[%|loc(report_param.value,report_param.owner_domain_min,report_param.owner_domain)%]Unable to reduce the number of list owners in required domains to %1. Domains that count toward the minimum requirement of %2: %3[%END%]
[%~ END ~%]
[%~ END ~%]
......@@ -2005,6 +2005,30 @@ our @params = (
'default' => 'off',
'file' => 'sympa.conf',
},
{ 'name' => 'owner_domain',
'sample' => 'domain1.tld,domain2.tld',
'gettext_id' => 'List of required domains for list owner addresses',
'file' => 'sympa.conf',
'optional' => '1',
'split_char' => ' ',
'vhost' => '1',
'edit' => '1',
'gettext_comment' =>
'Restrict list ownership to addresses in the specified domains. This can be used to reserve list ownership to a group of trusted users from a set of domains associated with an organization, while allowing editors and subscribers from the Internet at large.',
'default' => undef,
},
{ 'name' => 'owner_domain_min',
'sample' => '1',
'gettext_id' => 'Minimum number of list owners that must match owner_domain restriction',
'file' => 'sympa.conf',
'default' => '0',
'optional' => '1',
'vhost' => '1',
'edit' => '1',
'gettext_comment' =>
'Minimum number of list owners that must satisfy the owner_domain restriction. The default of zero (0) means *all* list owners must match. Setting to 1 requires only one list owner to match owner_domain; all other owners can be from any domain. This setting can be used to ensure that there is always at least one known contact point for a mailing list.',
},
{ 'name' => 'edit_list', #FIXME:maybe not used
'default' => 'owner',
'file' => 'sympa.conf',
......
......@@ -31,6 +31,8 @@ use Sympa::Robot;
use Sympa::Tools::Data;
use Sympa::Tools::Text;
my $log = Sympa::Log->instance;
sub new {
my $class = shift;
my $context = shift;
......@@ -774,6 +776,84 @@ sub _sanitize_changes_leaf {
}
}
#
# Global validations examine the entire configuration for semantic errors or
# requirements that can't be detected within a single paragraph.
#
# The 'owner_domain' option is an example of this need. The restriction applies
# to the entire set of owner addresses, not just a single owner.
#
# Error data is returned in a hashref with the usual keys.
#
my %global_validations = (
owner_domain => sub {
my $self = shift;
my $new = shift;
my $pinfo = $self->{_pinfo};
my $loglevel = 'debug'; # was set to 'info' during development
# gather parameters
my $owner_domain = $self->get('owner_domain');
if (defined($self->get_change('owner_domain'))) {
$owner_domain = $self->get_change('owner_domain');
}
(my $domainrex = "[.\@]($owner_domain)\$") =~ s/ /|/g;
my $owner_domain_min = $self->get('owner_domain_min');
if (defined($self->get_change('owner_domain_min'))) {
$owner_domain_min = $self->get_change('owner_domain_min');
}
$owner_domain_min ||= 0;
# if no owner_domain setting, do nothing
return if ($owner_domain =~ /^\s*$/);
# calculate updated owner list, including deletions
my @owner = map { $_->{'email'} } @{$self->get('owner')};
my $changes = $self->get_change('owner');
map { $owner[$_] = $changes->{$_}->{'email'} } CORE::keys %$changes;
@owner = grep defined, @owner;
# count matches and non-matches
my @non_matching_owners = grep {!/$domainrex/} @owner;
my @matching_owners = grep {/$domainrex/} @owner;
my $non_matching_count = 1 + $#non_matching_owners;
my $matching_owner_count = 1 + $#matching_owners;
# logging
$log->syslog($loglevel, "owner_domain: $owner_domain");
$log->syslog($loglevel, "owner_domain_min: $owner_domain_min");
$log->syslog($loglevel, "owners: " . join(",", @owner));
$log->syslog($loglevel, "total owners: " . ($#owner + 1));
$log->syslog($loglevel, "domainrex: $domainrex");
$log->syslog($loglevel, "matching_owners: " . join(",", @matching_owners));
$log->syslog($loglevel, "matching_owner_count: $matching_owner_count");
$log->syslog($loglevel, "non_matching_owners: " . join(",", @non_matching_owners));
$log->syslog($loglevel, "non_matching_count: $non_matching_count");
# apply different rules based on min domain requirement
if ($owner_domain_min == 0) {
return ('owner_domain',
{p_info => $pinfo->{'owner'},
p_paths => ['owner'],
owner_domain => $owner_domain,
value => join(' ', @non_matching_owners)})
unless ($non_matching_count == 0);
} else {
return ('owner_domain_min',
{p_info => $pinfo->{'owner'},
p_paths => ['owner'],
owner_domain => $owner_domain,
owner_domain_min => $owner_domain_min,
value => $matching_owner_count})
unless ($matching_owner_count >= $owner_domain_min);
}
return '';
},
);
# Validates changes on list configuration.
# Context:
# - $list: An instance of Sympa::List.
......@@ -815,6 +895,18 @@ sub _validate_changes {
$ret = 'invalid' if $r eq 'invalid';
}
# review the entire new configuration as a whole
foreach my $validation (CORE::keys %global_validations) {
next unless ref $global_validations{$validation} eq 'CODE';
my ($error, $err_info) = $global_validations{$validation}->($self, $new);
next unless $error;
push @$errors,
[
'user', $error, $err_info
];
$ret = 'invalid';
}
return '' unless %$new;
return $ret;
}
......
......@@ -320,6 +320,31 @@ our %pinfo = (
'default' => {'conf' => 'default_list_priority'}
},
'owner_domain' => {
order => 10.13,
'group' => 'description',
'gettext_id' => "Required domains for list owners",
'gettext_comment' =>
'Restrict list ownership to addresses in the specified domains.',
'format' => '[\w\.\- ]+', # same as Sympa::Regexps::host plus space
'length' => 72,
'occurrence' => '0-1',
'split_char' => ' ',
'default' => {'conf' => 'owner_domain'},
},
'owner_domain_min' => {
order => 10.14,
'group' => 'description',
'gettext_id' => "Minimum owners in required domains",
'gettext_comment' =>
'Require list ownership by a minimum number of addresses in the specified domains.',
'format' => '\d+',
'length' => 2,
'occurrence' => '0-1',
'default' => {'conf' => 'owner_domain_min'},
},
### Sending page ###
'send' => {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment