aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-29 02:03:21 +0200
committerGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-29 02:03:21 +0200
commit2bece6abde54881bb074dd44e7f87885eab4a777 (patch)
treebde87a2c98476847ab5082facade40062cb52e70
parentaa3340e58fc5b993bfc88070edf543a2ed82ef94 (diff)
Proper escaping of URIs.
-rw-r--r--TODO.org34
-rw-r--r--css/style.css3
-rw-r--r--lib/Fripost/Panel/Interface.pm142
-rw-r--r--lib/Fripost/Panel/Login.pm30
-rw-r--r--lib/Fripost/Schema/Alias.pm2
-rw-r--r--lib/Fripost/Schema/List.pm4
-rw-r--r--lib/Fripost/Schema/Local.pm2
-rw-r--r--lib/Fripost/Schema/Mailbox.pm2
-rw-r--r--misc/mklist/INSTALL4
-rwxr-xr-xmisc/mklist/mklist.pl4
-rw-r--r--template/add-alias.html8
-rw-r--r--template/add-list.html10
-rw-r--r--template/add-mailbox.html8
-rw-r--r--template/edit-alias.html10
-rw-r--r--template/edit-domain.html8
-rw-r--r--template/edit-list.html10
-rw-r--r--template/edit-mailbox.html14
-rw-r--r--template/list-domains.html8
-rw-r--r--template/list-locals.html29
19 files changed, 191 insertions, 141 deletions
diff --git a/TODO.org b/TODO.org
index 49c1154..d9aa4a1 100644
--- a/TODO.org
+++ b/TODO.org
@@ -1,4 +1,4 @@
-* DONE Email::Valid does not accept UTF-8 emails adresses (e.g., test@ƛ.net).
+* DONE Email::Valid does not accept UTF-8 emails adresses (e.g., peace@☮.net).
LDAP doesn't allow UTF-8 in the DNs anyway, so maybe convert the
domains/emails to Punycode internally?
@@ -17,6 +17,7 @@ Actually Postfix checks it and warns the administrator with a
in the logs. So it's fine to do a partial check here.
* TODO Write a script to check every runmode against the W3 validator.
+(Cf. cgiapp_postrun);
* DONE Use FastCGI. References
- http://www.cgi-app.org/index.cgi?FastCGI
@@ -24,10 +25,33 @@ in the logs. So it's fine to do a partial check here.
* TODO Use HTML::Template::Pro. Not sure it's really worth it, though.
-* TODO Forbid `/' and `\0' to appear in the domain/user name.
+* DONE Escape reserved characters in URLs:
+http://mark.stosberg.com/blog/2010/12/percent-encoding-uris-in-perl.html
-* TODO How should we encode the URL for internationalized domain names? Punicode vs. unicode vs. HTML entities?
-(Right now it's HTML entities.)
+* CANCELED How should we encode the URL for internationalized domain names? Punicode vs. unicode vs. HTML entities?
+CLOSED: [2012-09-27 Thu 00:03]
+- CLOSING NOTE [2012-09-27 Thu 00:03] \\
+It's up to the browser (Firefox support unicode in URLs).
-* TODO Forbid UTF8 in the domain part of lists? (Test if the list
+* CANCELED Forbid UTF8 in the domain part of lists? (Test if the list
managers support it at least.)
+CLOSED: [2012-09-27 Thu 03:38]
+- CLOSING NOTE [2012-09-27 Thu 03:38] \\
+Mailman and Schleuder do not support IDNs, but we convert the list name
+into punicode first.
+
+* TODO Give the right for domain owners and postmaster to grant the right
+to create aliases and lists.
+
+* TODO Give the right to appoint co owners (for list and aliases).
+
+* TODO Make every service use Kerberos, and remove the passphrase on
+their private keys.
+
+* TODO Check list names against mailman's and schleuder's regexps?
+
+* TODO What to do when a list creation fails? Set up a new service
+to clean out the pending lists and domains if they have not been fixed
+within 24h (daemon).
+
+* TODO Automatically generated passwords.
diff --git a/css/style.css b/css/style.css
index fa2f407..79fd1b6 100644
--- a/css/style.css
+++ b/css/style.css
@@ -14,6 +14,9 @@ body {
.active {
color: #32CD32;
}
+.pending {
+ color: #F77C13;
+}
h1, h2, h3 {
margin: 15pt auto 10pt auto;
width: 600pt;
diff --git a/lib/Fripost/Panel/Interface.pm b/lib/Fripost/Panel/Interface.pm
index f150a39..b9a9500 100644
--- a/lib/Fripost/Panel/Interface.pm
+++ b/lib/Fripost/Panel/Interface.pm
@@ -15,9 +15,9 @@ use parent 'Fripost::Panel::Login';
use Fripost::Schema;
use Fripost::Password;
-use HTML::Entities;
+use HTML::Entities 'encode_entities';
+use URI::Escape::XS 'encodeURIComponent';
use Net::IDN::Encode qw/email_to_unicode domain_to_ascii/;
-use CGI::Util qw/escape unescape/;
# This method is called right before the 'setup' method below. It
@@ -43,13 +43,11 @@ sub ListDomains : StartRunmode {
my @domains = $fp->domain->search( -concat => "\n", -die => 403);
$fp->done;
- my $template = $self->load_tmpl( 'list-domains.html', cache => 1, utf8 => 1
+ my $template = $self->load_tmpl( 'list-domains.html', cache => 1,
, loop_context_vars => 1
, global_vars => 1 );
- $template->param( url => $self->query->url
- , user_localpart => encode_entities($ul)
- , user_domainpart => encode_entities($ud)
- , domains => [ map { { domain => encode_entities($_->{domain})
+ $template->param( $self->userInfo );
+ $template->param( domains => [ map { { &mkLink( domain => $_->{domain})
, isactive => $_->{isactive}
, description => $_->{description} } }
@domains ]
@@ -65,8 +63,7 @@ sub ListLocals : Runmode {
my %CFG = $self->cfg;
my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
- my $d = decode_entities ((split /\//, $ENV{PATH_INFO}, 3)[1]);
- Encode::_utf8_on($d);
+ my $d = ($self->split_path)[1];
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
# Query *the* matching domain
@@ -77,18 +74,15 @@ sub ListLocals : Runmode {
# crash.
my @mailboxes = $fp->mailbox->search( $d );
my @aliases = $fp->alias->search( $d );
- my @lists = $fp->list->search( $d, -is_pending => 0 );
+ my @lists = $fp->list->search( $d );
$fp->done;
- my $template = $self->load_tmpl( 'list-locals.html', cache => 1, utf8 => 1
+ my $template = $self->load_tmpl( 'list-locals.html', cache => 1,
, loop_context_vars => 1
, global_vars => 1 );
- $template->param( url => $self->query->url
- , user_localpart => encode_entities($ul)
- , user_domainpart => encode_entities($ud)
- );
+ $template->param( $self->userInfo );
$template->param( domain => encode_entities($domain{domain})
, isactive => $domain{isactive}
, description => join ("\n", @{$domain{description}}) );
@@ -102,7 +96,7 @@ sub ListLocals : Runmode {
$template->param( listMailboxes => $#mailboxes >= 0 ||
$domain{permissions} =~ /p/ );
$template->param( mailboxes => [
- map { { user => encode_entities($_->{user})
+ map { { &mkLink(user => $_->{user})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
, forwards => [ map { {forward => encode_entities($_)} }
@@ -119,9 +113,7 @@ sub ListLocals : Runmode {
$template->param( listAliases => $#aliases >= 0 ||
$domain{permissions} =~ /[aop]/ );
$template->param( aliases => [
- map { my $a = escape(encode_entities($_->{alias})); # TODO
- { aliasurl => escape($a)
- , alias => $a
+ map { { &mkLink(alias => $_->{alias})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
, destinations => [ map { {destination => encode_entities($_)} }
@@ -139,11 +131,13 @@ sub ListLocals : Runmode {
# Should we list lists?
$template->param( listLists => $#lists >= 0 || $domain{permissions} =~ /[lop]/ );
$template->param( lists => [
- map { { list => encode_entities($_->{list})
+ map { { &mkLink(list => $_->{list})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
+ , ispending => $_->{ispending}
, transport => $_->{transport}
- , listurl => $CFG{'listurl_'.$_->{transport}}.$_->{list}.'@'.domain_to_ascii($d)
+ , listURL => $CFG{'listurl_'.$_->{transport}}.$_->{list}.
+ '@'.domain_to_ascii($d)
};
}
@lists
@@ -159,11 +153,10 @@ sub EditDomain : Runmode {
my %CFG = $self->cfg;
my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
- my $d = decode_entities ((split /\//, $ENV{PATH_INFO}, 3)[1]);
- Encode::_utf8_on($d);
+ my $d = ($self->split_path)[1];
my $q = $self->query;
- return $self->redirect($q->url .'/') if defined $q->param('cancel');
+ return $self->redirect('./') if defined $q->param('cancel');
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
@@ -180,14 +173,11 @@ sub EditDomain : Runmode {
my %domain = $fp->domain->get( $d, -die => 404 );
$fp->done;
- my $template = $self->load_tmpl( 'edit-domain.html', cache => 1, utf8 => 1
+ my $template = $self->load_tmpl( 'edit-domain.html', cache => 1,
, loop_context_vars => 1
, global_vars => 1 );
- $template->param( url => $q->url
- , user_localpart => encode_entities($ul)
- , user_domainpart => encode_entities($ud)
- , domain => encode_entities($d)
- );
+ $template->param( $self->userInfo );
+ $template->param( domain => encode_entities($d) );
if ($error) {
# Preserve the (incorrect) form
$template->param( isactive => $q->param('isactive')
@@ -214,38 +204,35 @@ sub EditLocal : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
- my ($null,$d,$l,$crap) = split /\//, $ENV{PATH_INFO}, 4;
- my $du = decode_entities ($d); Encode::_utf8_on($du);
- my $lu = decode_entities ($l); Encode::_utf8_on($lu);
-
my $q = $self->query;
- return $self->redirect($q->url.'/'.$d.'/') if defined $q->param('cancel');
+ return $self->redirect('../') if defined $q->param('cancel');
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
# Search for *the* matching mailbox, alias or list.
- my %local = $fp->local->get ($lu.'@'.$du, -die => 404,
- -concat => "\x{0D}\x{0A}" );
+ my ($d,$l) = ($self->split_path)[1,2];
+ my %local = $fp->local->get ($l.'@'.$d, -die => 404,
+ -concat => "\x{0D}\x{0A}" );
die "Unknown type" unless grep { $local{type} eq $_ }
qw/mailbox alias list/;
+ die "404\n" if $local{ispending};
my $error; # Tells whether the change submission has failed.
my $t = $local{type};
if (defined $q->param('a') and $q->param('a') eq 'delete') {
# Delete the entry
- $error = $fp->$t->delete($lu.'@'.$du, -die => 0);
+ $error = $fp->$t->delete($l.'@'.$d, -die => 0);
unless ($error) {
$fp->done;
- return $self->redirect($q->url .'/'. $d .'/');
+ return $self->redirect('../');
}
}
if (defined $q->param('submit')) {
# Changes have been submitted: process them
my %entry;
if ($t eq 'mailbox') {
- $entry{user} = $lu.'@'.$du;
+ $entry{user} = $l.'@'.$d;
$entry{forwards} = $q->param('forwards');
if ($q->param('oldpw') ne '' or
@@ -282,11 +269,11 @@ sub EditLocal : Runmode {
}
}
elsif ($t eq 'alias') {
- $entry{alias} = $lu.'@'.$du;
+ $entry{alias} = $l.'@'.$d;
$entry{maildrop} = $q->param('maildrop');
}
elsif ($t eq 'list') {
- $entry{list} = $lu.'@'.$du;
+ $entry{list} = $l.'@'.$d;
$entry{transport} = $q->param('transport');
}
$entry{isactive} = $q->param('isactive');
@@ -295,13 +282,10 @@ sub EditLocal : Runmode {
unless $error;
}
- my $template = $self->load_tmpl( "edit-$t.html",
- cache => 1, utf8 => 1 );
- $template->param( url => $q->url
- , user_localpart => encode_entities($ul)
- , user_domainpart => encode_entities($ud)
- , domain => encode_entities($du)
- );
+ my $template = $self->load_tmpl( "edit-$t.html", cache => 1 );
+ $template->param( $self->userInfo );
+ $template->param( domain => encode_entities($d) );
+
if ($error and defined $q->param('submit')) {
# Preserve the (incorrect) form, except the passwords
if ($t eq 'mailbox') {
@@ -319,8 +303,8 @@ sub EditLocal : Runmode {
, description => $q->param('description') );
}
else {
- %local = $fp->local->get ($lu.'@'.$du, -die => 404,
- -concat => "\x{0D}\x{0A}" );
+ %local = $fp->local->get ($l.'@'.$d, -die => 404,
+ -concat => "\x{0D}\x{0A}" );
if ($t eq 'mailbox') {
$template->param( user => encode_entities($local{user})
, forwards => encode_entities($local{forwards}) );
@@ -340,8 +324,8 @@ sub EditLocal : Runmode {
(defined $q->param('a') and $q->param('a') eq 'delete'));
$template->param( newChanges => $news );
$template->param( error => encode_entities ($error) ) if $error;
- $template->param( canDelete => 1 ) if $t eq 'alias'; # TODO
- $template->param( listurl => $CFG{'listurl_'.$local{transport}}.$l.'@'.$d )
+ $template->param( canDelete => 1 ) if $t eq 'alias';
+ $template->param( listURL => $CFG{'listurl_'.$local{transport}}.$l.'@'.$d )
if $t eq 'list';
$q->delete('a');
return $template->output;
@@ -354,13 +338,10 @@ sub AddLocal : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
- my $d = (split /\//, $ENV{PATH_INFO}, 3)[1];
- my $du = decode_entities ($d); Encode::_utf8_on($du);
-
my $q = $self->query;
- return $self->redirect($q->url.'/'.$d.'/') if defined $q->param('cancel');
+ return $self->redirect('./') if defined $q->param('cancel');
+ my $d = ($self->split_path)[1];
my $t = $q->param('t') // die "Undefined type";
my $error; # Tells whether the change submission has failed.
if (defined $q->param('submit')) {
@@ -368,7 +349,7 @@ sub AddLocal : Runmode {
my %entry;
my %rest;
if ($t eq 'mailbox') {
- $entry{user} = $q->param('user').'@'.$du;
+ $entry{user} = $q->param('user').'@'.$d;
$entry{forwards} = $q->param('forwards');
if ($q->param('password') ne $q->param('password2')) {
$error = "Passwords do not match";
@@ -384,11 +365,11 @@ sub AddLocal : Runmode {
# TODO: inherit the quota from the postmaster's?
}
elsif ($t eq 'alias') {
- $entry{alias} = $q->param('alias').'@'.$du;
+ $entry{alias} = $q->param('alias').'@'.$d;
$entry{maildrop} = $q->param('maildrop');
}
elsif ($t eq 'list') {
- $entry{list} = $q->param('list').'@'.$du;
+ $entry{list} = $q->param('list').'@'.$d;
$entry{transport} = $q->param('transport');
if ($q->param('password') ne $q->param('password2')) {
$error = "Passwords do not match";
@@ -409,7 +390,7 @@ sub AddLocal : Runmode {
}
else {
# Unknown type
- return $self->redirect($q->url.'/'.$d.'/');
+ return $self->redirect('./');
}
$entry{isactive} = $q->param('isactive');
$entry{description} = $q->param('description');
@@ -418,16 +399,13 @@ sub AddLocal : Runmode {
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
$error = $fp->$t->add( \%entry, -concat => "(\n|\x{0D}\x{0A})", %rest);
$fp->done;
- return $self->redirect($q->url.'/'.$d.'/') unless $error;
+ return $self->redirect('./') unless $error;
}
}
- my $template = $self->load_tmpl( "add-$t.html", cache => 1, utf8 => 1 );
- $template->param( url => $q->url
- , user_localpart => encode_entities($ul)
- , user_domainpart => encode_entities($ud)
- , domain => encode_entities($du)
- );
+ my $template = $self->load_tmpl( "add-$t.html", cache => 1 );
+ $template->param( $self->userInfo );
+ $template->param( domain => encode_entities($d) );
if ($error) {
# Preserve the (incorrect) form, except the passwords
if ($t eq 'mailbox') {
@@ -444,7 +422,7 @@ sub AddLocal : Runmode {
}
else {
# Unknown type
- return $self->redirect($q->url.'/'.$d.'/');
+ return $self->redirect('./');
}
$template->param( isactive => $q->param('isactive')
, description => $q->param('description')
@@ -456,6 +434,28 @@ sub AddLocal : Runmode {
return $template->output;
}
+sub mkURL {
+ my $host = shift;
+ my @path = map { encodeURIComponent($_) } @_;
+ join '/', ($host, @path);
+}
+
+sub mkLink {
+ my $k = shift;
+ my $d = shift;
+ ( $k => encode_entities($d),
+ $k.'URI' => &mkURL('.', $d) )
+}
+
+sub userInfo {
+ my $self = shift;
+ my ($l,$d) = split /\@/, email_to_unicode($self->authen->username), 2;
+
+ ( user_localpart => encode_entities($l)
+ , user_domainpart => encode_entities($d)
+ , userURI => &mkURL ($ENV{SCRIPT_NAME}, $d, $l)
+ )
+}
=head1 AUTHOR
diff --git a/lib/Fripost/Panel/Login.pm b/lib/Fripost/Panel/Login.pm
index 86b3e66..810f9e1 100644
--- a/lib/Fripost/Panel/Login.pm
+++ b/lib/Fripost/Panel/Login.pm
@@ -20,8 +20,9 @@ use CGI::Application::Plugin::Redirect;
use CGI::Application::Plugin::ConfigAuto 'cfg';
use Fripost::Schema;
-use HTML::Entities;
-use Net::IDN::Encode qw/email_to_ascii/;
+use HTML::Entities 'encode_entities';
+use URI::Escape::XS 'decodeURIComponent';
+use Net::IDN::Encode 'email_to_ascii';
# This method is called right before the 'setup' method below. It
@@ -62,7 +63,7 @@ sub cgiapp_init {
$u .= '@'.$CFG{default_realm};
}
Encode::_utf8_on($u);
- $u = Net::IDN::Encode::email_to_ascii($u);
+ $u = email_to_ascii($u);
my $fp = Fripost::Schema::->auth($u, $p,
ldap_uri => $CFG{ldap_uri},
ldap_suffix => $CFG{ldap_suffix},
@@ -80,7 +81,7 @@ sub cgiapp_init {
);
# The run modes that require authentication
- $self->authen->protected_runmodes( qw /okay error_rm/ );
+ $self->authen->protected_runmodes( qw/okay error_rm/ );
}
@@ -105,7 +106,7 @@ sub setup {
return 'logout' if defined $a and $a eq 'logout';
# /domain/{user,alias,list}/?query_url
- my ($null,$domain,$local,$crap) = split /\//, $ENV{PATH_INFO};
+ my ($null,$domain,$local,$crap) = $self->split_path;
return 'ListDomains' unless (defined $null) and $null eq '';
@@ -164,7 +165,7 @@ sub login : Runmode {
sub login_box {
my $self = shift;
- my $template = $self->load_tmpl( 'login.html', cache => 1, utf8 => 1 );
+ my $template = $self->load_tmpl( 'login.html', cache => 1 );
$template->param( error => $self->authen->login_attempts );
$template->param( redirect => $self->query->param('redirect') );
@@ -199,7 +200,7 @@ sub error_rm : ErrorRunmode {
# HTTP client error.
chomp $error;
$self->header_props ( -status => $error );
- my $template = $self->load_tmpl( 'error_http.html', cache => 1, utf8 => 1 );
+ my $template = $self->load_tmpl( 'error_http.html', cache => 1 );
my $mesg;
if ($error eq '403' ) {
$mesg = 'Forbidden'
@@ -214,7 +215,7 @@ sub error_rm : ErrorRunmode {
else {
# Users are not supposed to see that unless the CGI crashes :P
- my $template = $self->load_tmpl( 'error.html', cache => 1, utf8 => 1 );
+ my $template = $self->load_tmpl( 'error.html', cache => 1 );
$template->param( email => $self->cfg('report_email') );
$template->param( message => $error );
$template->param( url => $self->query->url . '/');
@@ -222,6 +223,19 @@ sub error_rm : ErrorRunmode {
}
}
+sub split_path {
+ my $self = shift;
+ my %options = @_;
+
+ my $script = $ENV{SCRIPT_NAME} // '';
+ my $uri = $self->query->request_uri;
+ $uri =~ s/^$script//s;
+ $uri =~ s/\?.*//s;
+
+ map { my $x = decodeURIComponent($_); Encode::_utf8_on($x); $x }
+ (split /\//, $uri);
+}
+
=head1 AUTHOR
diff --git a/lib/Fripost/Schema/Alias.pm b/lib/Fripost/Schema/Alias.pm
index 07ae84f..51bf98f 100644
--- a/lib/Fripost/Schema/Alias.pm
+++ b/lib/Fripost/Schema/Alias.pm
@@ -111,8 +111,8 @@ sub add {
}
eval {
+ die "Missing alias name\n" unless $a->{alias} =~ /^.+\@.+$/;
my ($l,$d) = split /\@/, email_to_ascii($a->{alias}), 2;
- die "Missing alias name\n" if $l eq '';
&_is_valid($a);
die "‘".$a->{alias}."’ already exists\n"
if $self->local->exists($a->{alias},%options);
diff --git a/lib/Fripost/Schema/List.pm b/lib/Fripost/Schema/List.pm
index 87876f6..67da859 100644
--- a/lib/Fripost/Schema/List.pm
+++ b/lib/Fripost/Schema/List.pm
@@ -51,6 +51,7 @@ sub search {
deref => 'never',
filter => $filter,
attrs => [ qw/fvl description fripostIsStatusActive
+ fripostIsStatusPending
fripostListManager/ ]
);
if ($lists->code) {
@@ -61,6 +62,7 @@ sub search {
, isactive => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $_->get_value('description'))
, transport => $_->get_value('fripostListManager')
+ , ispending => ($_->get_value('fripostIsStatusPending') // '') eq 'TRUE'
}
}
$lists->sorted('fvl')
@@ -113,8 +115,8 @@ sub add {
eval {
+ die "Missing list name\n" unless $l->{list} =~ /^.+\@.+$/;
my ($l2,$d) = split /\@/, email_to_ascii($l->{list}), 2;
- die "Missing list name\n" if $l eq '';
must_attrs( $l, 'transport' );
&_is_valid($l);
die "‘".$l->{list}."’ already exists\n"
diff --git a/lib/Fripost/Schema/Local.pm b/lib/Fripost/Schema/Local.pm
index 9efff91..f497a4e 100644
--- a/lib/Fripost/Schema/Local.pm
+++ b/lib/Fripost/Schema/Local.pm
@@ -49,6 +49,7 @@ sub get {
(&(objectClass=FripostVirtualList)(fvl=$l)))",
attrs => [ qw/fvu description
fripostIsStatusActive
+ fripostIsStatusPending
fripostOptionalMaildrop
fripostMailboxQuota
fva fripostMaildrop
@@ -91,6 +92,7 @@ sub get {
}
$ret{isactive} = $local->get_value('fripostIsStatusActive') eq 'TRUE';
$ret{description} = concat($concat, $local->get_value('description'));
+ $ret{ispending} = ($local->get_value('fripostIsStatusPending') // '') eq 'TRUE';
return %ret;
}
diff --git a/lib/Fripost/Schema/Mailbox.pm b/lib/Fripost/Schema/Mailbox.pm
index 95e2d10..ce23d98 100644
--- a/lib/Fripost/Schema/Mailbox.pm
+++ b/lib/Fripost/Schema/Mailbox.pm
@@ -134,8 +134,8 @@ sub add {
}
eval {
+ die "Missing user name\n" unless $m->{user} =~ /^.+\@.+$/;
my ($l,$d) = split /\@/, email_to_ascii($m->{user}), 2;
- die "Missing user name\n" if $l eq '';
&_is_valid($m);
die "‘".$m->{user}."’ already exists\n"
if $self->local->exists($m->{user},%options);
diff --git a/misc/mklist/INSTALL b/misc/mklist/INSTALL
index 660bcf9..7164217 100644
--- a/misc/mklist/INSTALL
+++ b/misc/mklist/INSTALL
@@ -37,7 +37,7 @@ Postfix's master.cf
mklist-mailman unix - n n - - pipe
flags=FR directory=/opt/fripost-panel/ user=list:list
argv=/opt/fripost-panel/misc/mklist/mklist.pl mailman ${size}
-
+
mklist-schleuder unix - n n - - pipe
flags=FR directory=/opt/fripost-panel/ user=schleuder:schleuder
argv=/opt/fripost-panel/misc/mklist/mklist.pl schleuder ${size}
@@ -50,7 +50,7 @@ Postfix's main.cf
mklist-mailman_destination_concurrency_limit = 1
mklist-mailman_destination_recpipient_limit = 1
mklist-mailman_time_limit = 10m
-
+
mklist-schleuder_destination_concurrency_limit = 1
mklist-schleuder_destination_recpipient_limit = 1
mklist-schleuder_time_limit = 2h
diff --git a/misc/mklist/mklist.pl b/misc/mklist/mklist.pl
index 3223c45..6d0b6b2 100755
--- a/misc/mklist/mklist.pl
+++ b/misc/mklist/mklist.pl
@@ -30,14 +30,14 @@ use lib 'lib';
use Mail::GnuPG;
use MIME::Parser;
use MIME::QuotedPrint;
-use Net::IDN::Encode qw/email_to_ascii/;
+use Net::IDN::Encode 'email_to_ascii';
use Fripost::Schema;
my $transport = shift;
pod2usage(2) unless defined $transport and
grep { $transport eq $_}
qw/mailman schleuder/;
-my $configdir = catdir('/','etc','mklist');
+my $configdir = catdir(qw(/ etc mklist));
my $config = Config::Auto::parse( catfile($configdir, 'config'),
format => "equal" );
diff --git a/template/add-alias.html b/template/add-alias.html
index 7ceb4cf..8ad887f 100644
--- a/template/add-alias.html
+++ b/template/add-alias.html
@@ -8,13 +8,13 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../">Root</a> /
+ <a href="./"><TMPL_VAR NAME=domain></a> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
diff --git a/template/add-list.html b/template/add-list.html
index ef99497..e69690b 100644
--- a/template/add-list.html
+++ b/template/add-list.html
@@ -8,13 +8,13 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../">Root</a> /
+ <a href="./"><TMPL_VAR NAME=domain></a> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
@@ -103,7 +103,7 @@
<i>Note</i>: No confirmation email will be sent. It may take a while for the list to be created (especially
for the Schleuder list manager, as it requires a GPG key creation); Once the list has succefully been created,
it will be visible under the
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/">management page for <span class="domain"><TMPL_VAR NAME=domain></span></a>.
+ <a href="./">management page for <span class="domain"><TMPL_VAR NAME=domain></span></a>.
</div>
</div>
</form>
diff --git a/template/add-mailbox.html b/template/add-mailbox.html
index d82af0e..6bcc748 100644
--- a/template/add-mailbox.html
+++ b/template/add-mailbox.html
@@ -8,13 +8,13 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../">Root</a> /
+ <a href="./"><TMPL_VAR NAME=domain></a> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
diff --git a/template/edit-alias.html b/template/edit-alias.html
index 85e2d5f..aa18faf 100644
--- a/template/edit-alias.html
+++ b/template/edit-alias.html
@@ -8,14 +8,14 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../../">Root</a> /
+ <a href="../"><TMPL_VAR NAME=domain></a> /
<TMPL_VAR NAME=alias> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
@@ -23,7 +23,7 @@
<div id="content">
<h1>Edit alias <span class="email"><TMPL_VAR NAME=alias>@<TMPL_VAR NAME=domain></span><TMPL_IF NAME=canDelete
- ><span class="action">[<a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/<TMPL_VAR NAME=alias>/?a=delete">delete</a>]</span
+ ><span class="action">[<a href="./?a=delete">delete</a>]</span
></TMPL_IF></h1>
<TMPL_IF NAME=newChanges>
diff --git a/template/edit-domain.html b/template/edit-domain.html
index e6373e8..a6d6b34 100644
--- a/template/edit-domain.html
+++ b/template/edit-domain.html
@@ -8,13 +8,13 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../">Root</a> /
+ <a href="./"><TMPL_VAR NAME=domain></a> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
diff --git a/template/edit-list.html b/template/edit-list.html
index f44e38c..1cc8148 100644
--- a/template/edit-list.html
+++ b/template/edit-list.html
@@ -8,21 +8,21 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../../">Root</a> /
+ <a href="../"><TMPL_VAR NAME=domain></a> /
<TMPL_VAR NAME=list> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
<hr/>
<div id="content">
- <h1>Edit list <a class="external" target="_blank" href="<TMPL_VAR NAME=listurl>"
+ <h1>Edit list <a class="external" target="_blank" href="<TMPL_VAR NAME=listURL>"
><span class="email"><TMPL_VAR NAME=list>@<TMPL_VAR NAME=domain></span
></a></h1>
diff --git a/template/edit-mailbox.html b/template/edit-mailbox.html
index 5f5dc08..892c643 100644
--- a/template/edit-mailbox.html
+++ b/template/edit-mailbox.html
@@ -8,14 +8,14 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> /
- <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a> /
+ <a href="../../">Root</a> /
+ <a href="../"><TMPL_VAR NAME=domain></a> /
<TMPL_VAR NAME=user> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
@@ -71,9 +71,11 @@
<div class="help">
<i>Note</i>:
- You need to enter
- <span class="mailbox"><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></span>'s
+ You need to enter your
+ (<span class="mailbox"><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></span>'s)
current password first.
+ Leave these fields empty if you do not want to change the
+ password.
</div>
<hr/>
diff --git a/template/list-domains.html b/template/list-domains.html
index 980b8de..5ebdd05 100644
--- a/template/list-domains.html
+++ b/template/list-domains.html
@@ -11,16 +11,16 @@
Root /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
<hr/>
<div id="content">
- <h1>Manage domains<span class="action">[<a href="<TMPL_VAR NAME=url>/?a=add">add</a>]</span></h1>
+ <h1>Manage domains<span class="action">[<a href="./?a=add">add</a>]</span></h1>
<table class="list" id="domains">
<thead>
@@ -33,7 +33,7 @@
<tbody>
<TMPL_LOOP NAME=domains>
<TMPL_IF NAME=__even__><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
- <td><span class="domain"><a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/"><TMPL_VAR NAME=domain></a></span></td>
+ <td><span class="domain"><a href="<TMPL_VAR NAME=domainURI>/"><TMPL_VAR NAME=domain></a></span></td>
<td><TMPL_IF NAME=description><TMPL_VAR NAME=description><TMPL_ELSE><span class="none">(none)</span></TMPL_IF></td>
<td><TMPL_IF NAME=isactive><span class="active">&#x2714;</span><TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></td>
</tr>
diff --git a/template/list-locals.html b/template/list-locals.html
index cb6f057..40ebeec 100644
--- a/template/list-locals.html
+++ b/template/list-locals.html
@@ -8,12 +8,12 @@
<body>
<div id="header">
<div class="left column">
- <a href="<TMPL_VAR NAME=url>/">Root</a> / <TMPL_VAR NAME=domain> /
+ <a href="../">Root</a> / <TMPL_VAR NAME=domain> /
</div>
<div class="right column">
- Logged as <a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=user_domainpart>/<TMPL_VAR NAME=user_localpart>/?a=edit"
+ Logged as <a href="<TMPL_VAR NAME=userURI>/?a=edit"
><TMPL_VAR NAME=user_localpart>@<TMPL_VAR NAME=user_domainpart></a>
- | <a href="<TMPL_VAR NAME=url>/?a=logout">Log out</a>
+ | <a href="./?a=logout">Log out</a>
</div>
<br/>
</div>
@@ -21,7 +21,7 @@
<div id="content">
<h1>Manage domain <span class="domain"><TMPL_VAR NAME=domain></span
- ><TMPL_IF NAME=canEditDomain><span class="action">[<a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/?a=edit">edit domain</a>]</span></TMPL_IF></h1>
+ ><TMPL_IF NAME=canEditDomain><span class="action">[<a href="./?a=edit">edit domain</a>]</span></TMPL_IF></h1>
<TMPL_IF NAME=description><p class="description"><TMPL_VAR NAME=description></p></TMPL_IF>
@@ -36,7 +36,7 @@
<TMPL_IF NAME=listMailboxes>
<h3>Mailboxes<TMPL_IF NAME=canAddMailbox
- ><span class="action">[<a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/?a=add&amp;t=mailbox">add</a>]</span
+ ><span class="action">[<a href="./?a=add&amp;t=mailbox">add</a>]</span
></TMPL_IF></h3>
<table class="list" id="mailboxes">
@@ -52,7 +52,7 @@
<tbody>
<TMPL_LOOP NAME=mailboxes>
<TMPL_IF NAME=__even__><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
- <td><span class="mailbox"><a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/<TMPL_VAR NAME=user>/"><TMPL_VAR NAME=user></a></span></td>
+ <td><span class="mailbox"><a href="<TMPL_VAR NAME=userURI>/"><TMPL_VAR NAME=user></a></span></td>
<td><TMPL_IF NAME=description><TMPL_VAR NAME=description><TMPL_ELSE><span class="none">(none)</span></TMPL_IF></td>
<td><TMPL_IF NAME=isactive><span class="active">&#x2714;</span><TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></td>
<td><TMPL_UNLESS NAME=forwards><span class="none">(none)</span></TMPL_UNLESS>
@@ -69,7 +69,7 @@
<TMPL_IF NAME=listAliases>
<h3>Alias<TMPL_IF NAME=canAddAlias
- ><span class="action">[<a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/?a=add&amp;t=alias">add</a>]</span
+ ><span class="action">[<a href="./?a=add&amp;t=alias">add</a>]</span
></TMPL_IF></h3>
<table class="list" id="aliases">
@@ -84,7 +84,7 @@
<tbody>
<TMPL_LOOP NAME=aliases>
<TMPL_IF NAME=__even__><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
- <td><span class="alias"><a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/<TMPL_VAR NAME=aliasurl>/"><TMPL_VAR NAME=alias></a></span></td>
+ <td><span class="alias"><a href="<TMPL_VAR NAME=aliasURI>/"><TMPL_VAR NAME=alias></a></span></td>
<td><TMPL_IF NAME=description><TMPL_VAR NAME=description><TMPL_ELSE><span class="none">(none)</span></TMPL_IF></td>
<td><TMPL_IF NAME=isactive><span class="active">&#x2714;</span><TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></td>
<td><TMPL_UNLESS NAME=destinations><span class="none">(none)</span></TMPL_UNLESS>
@@ -93,7 +93,7 @@
</TMPL_LOOP>
<TMPL_IF NAME=catchalls>
<TMPL_IF NAME=CAodd><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
- <td><a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/?a=edit#catch-all">*</a></td>
+ <td><a href="./?a=edit#catch-all">*</a></td>
<td>Catch-all alias(es) for domain <span class="domain"><TMPL_VAR NAME=domain></span>.</td>
<td><span class="dunno">&#x2014;</span></td>
<td><TMPL_LOOP NAME=catchalls><span class="email"><TMPL_VAR NAME=catchall></span><TMPL_UNLESS NAME=__last__>, </TMPL_UNLESS></TMPL_LOOP></td>
@@ -107,7 +107,7 @@
<TMPL_IF NAME=listLists>
<h3>Lists<TMPL_IF NAME=canAddList
- ><span class="action">[<a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/?a=add&amp;t=list">add</a>]</span
+ ><span class="action">[<a href="./?a=add&amp;t=list">add</a>]</span
></TMPL_IF></h3>
<table class="list" id="lists">
@@ -122,10 +122,13 @@
<tbody>
<TMPL_LOOP NAME=lists>
<TMPL_IF NAME=__even__><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
- <td><span class="list"><a href="<TMPL_VAR NAME=url>/<TMPL_VAR NAME=domain>/<TMPL_VAR NAME=list>/"><TMPL_VAR NAME=list></a></span
- > <a class="external" target="_blank" href="<TMPL_VAR NAME=listurl>">➠</a></td>
+ <td><span class="list"><TMPL_UNLESS NAME=ispending><a href="./<TMPL_VAR NAME=listURI>/"></TMPL_UNLESS
+ ><TMPL_VAR NAME=list
+ ><TMPL_UNLESS NAME=ispending></a> <a class="external" target="_blank" href="<TMPL_VAR NAME=listURL>">&#x27A0;</a></TMPL_UNLESS></span></td>
<td><TMPL_IF NAME=description><TMPL_VAR NAME=description><TMPL_ELSE><span class="none">(none)</span></TMPL_IF></td>
- <td><TMPL_IF NAME=isactive><span class="active">&#x2714;</span><TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></td>
+ <td><TMPL_IF NAME=ispending><span class="pending">&#x2691;</span>
+ <TMPL_ELSE><TMPL_IF NAME=isactive><span class="active">&#x2714;</span>
+ <TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></TMPL_IF></td>
<td><TMPL_VAR NAME=transport></td>
</tr>
</TMPL_LOOP>