mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2024-12-09 08:50:05 +08:00
commit
facebbddaa
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ data/conf/dovecot/dovecot-master.passwd
|
||||
mailcow.conf
|
||||
mailcow.conf_backup
|
||||
data/conf/nginx/listen.active
|
||||
data/web/inc/vars.local.inc.php
|
||||
|
@ -19,13 +19,46 @@ RUN apt-get -y install dovecot-common \
|
||||
dovecot-mysql \
|
||||
dovecot-pop3d \
|
||||
dovecot-dev \
|
||||
syslog-ng \
|
||||
syslog-ng-core \
|
||||
ca-certificates \
|
||||
supervisor \
|
||||
wget \
|
||||
curl \
|
||||
build-essential \
|
||||
autotools-dev \
|
||||
automake
|
||||
automake \
|
||||
libauthen-ntlm-perl \
|
||||
libcrypt-ssleay-perl \
|
||||
libdigest-hmac-perl \
|
||||
libfile-copy-recursive-perl \
|
||||
libio-compress-perl \
|
||||
libio-socket-inet6-perl \
|
||||
libio-socket-ssl-perl \
|
||||
libio-tee-perl \
|
||||
libmodule-scandeps-perl \
|
||||
libnet-ssleay-perl \
|
||||
libpar-packer-perl \
|
||||
libreadonly-perl \
|
||||
libterm-readkey-perl \
|
||||
libtest-pod-perl \
|
||||
libtest-simple-perl \
|
||||
libunicode-string-perl \
|
||||
liburi-perl \
|
||||
libdbi-perl \
|
||||
liblockfile-simple-perl \
|
||||
libdbd-mysql-perl \
|
||||
libipc-run-perl \
|
||||
make \
|
||||
cpanminus
|
||||
|
||||
RUN sed -i -E 's/^(\s*)system\(\);/\1unix-stream("\/dev\/log");/' /etc/syslog-ng/syslog-ng.conf
|
||||
RUN cpanm Data::Uniqid Mail::IMAPClient String::Util
|
||||
RUN echo '* * * * * root /usr/local/bin/imapsync_cron.pl' > /etc/cron.d/imapsync
|
||||
RUN echo '30 3 * * * vmail /usr/bin/doveadm quota recalc -A' > /etc/cron.d/dovecot-sync
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
RUN wget http://hg.dovecot.org/dovecot-antispam-plugin/archive/tip.tar.gz -O - | tar xvz \
|
||||
&& cd /tmp/dovecot-antispam* \
|
||||
&& ./autogen.sh \
|
||||
@ -33,10 +66,15 @@ RUN wget http://hg.dovecot.org/dovecot-antispam-plugin/archive/tip.tar.gz -O - |
|
||||
&& make \
|
||||
&& make install
|
||||
|
||||
COPY ./imapsync /usr/local/bin/imapsync
|
||||
COPY ./postlogin.sh /usr/local/bin/postlogin.sh
|
||||
COPY ./imapsync_cron.pl /usr/local/bin/imapsync_cron.pl
|
||||
COPY ./rspamd-pipe /usr/local/bin/rspamd-pipe
|
||||
COPY ./docker-entrypoint.sh /
|
||||
COPY ./supervisord.conf /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN chmod +x /usr/local/bin/rspamd-pipe
|
||||
RUN chmod +x /usr/local/bin/imapsync_cron.pl
|
||||
|
||||
RUN groupadd -g 5000 vmail
|
||||
RUN useradd -g vmail -u 5000 vmail -d /var/vmail
|
||||
@ -44,6 +82,6 @@ RUN useradd -g vmail -u 5000 vmail -d /var/vmail
|
||||
EXPOSE 24 10001
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["/usr/sbin/dovecot", "-F"]
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
@ -1,11 +1,17 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Set config parameters, escape " in db password
|
||||
# Hard-code env vars to imapsync due to cron not passing them to the perl script
|
||||
sed -i "/^\$DBUSER/c\\\$DBUSER='${DBUSER}';" /usr/local/bin/imapsync_cron.pl
|
||||
sed -i "/^\$DBPASS/c\\\$DBPASS='${DBPASS}';" /usr/local/bin/imapsync_cron.pl
|
||||
sed -i "/^\$DBNAME/c\\\$DBNAME='${DBNAME}';" /usr/local/bin/imapsync_cron.pl
|
||||
|
||||
# Set Dovecot config parameters, escape " in db password
|
||||
DBPASS=$(echo ${DBPASS} | sed 's/"/\\"/g')
|
||||
sed -i "/^connect/c\connect = \"host=mysql dbname=${DBNAME} user=${DBUSER} password=${DBPASS}\"" /etc/dovecot/sql/*
|
||||
|
||||
[[ ! -d /var/vmail/sieve ]] && mkdir -p /var/vmail/sieve
|
||||
[[ ! -d /etc/sogo ]] && mkdir -p /etc/sogo
|
||||
cat /etc/dovecot/sieve_after > /var/vmail/sieve/global.sieve
|
||||
sievec /var/vmail/sieve/global.sieve
|
||||
chown -R vmail:vmail /var/vmail/sieve
|
||||
|
9488
data/Dockerfiles/dovecot/imapsync
Executable file
9488
data/Dockerfiles/dovecot/imapsync
Executable file
File diff suppressed because it is too large
Load Diff
72
data/Dockerfiles/dovecot/imapsync_cron.pl
Executable file
72
data/Dockerfiles/dovecot/imapsync_cron.pl
Executable file
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use DBI;
|
||||
use File::Temp qw/ mkstemp /;
|
||||
use LockFile::Simple qw(lock trylock unlock);
|
||||
use Data::Dumper qw(Dumper);
|
||||
use IPC::Run 'run';
|
||||
use String::Util 'trim';
|
||||
|
||||
$DBNAME = '';
|
||||
$DBUSER = '';
|
||||
$DBPASS = '';
|
||||
|
||||
$run_dir="/tmp";
|
||||
$dsn = "DBI:mysql:database=" . $DBNAME . ";host=mysql";
|
||||
$lock_file = $run_dir . "/imapsync_busy";
|
||||
$lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1);
|
||||
$lockmgr->lock($lock_file) || die "can't lock ${lock_file}";
|
||||
$dbh = DBI->connect($dsn, $DBUSER, $DBPASS);
|
||||
open my $file, '<', "/etc/sogo/sieve.creds";
|
||||
my $creds = <$file>;
|
||||
close $file;
|
||||
my ($master_user, $master_pass) = split /:/, $creds;
|
||||
my $sth = $dbh->prepare("SELECT id, user1, user2, host1, authmech1, password1, exclude, port1, enc1, delete2duplicates, maxage, subfolder2 FROM imapsync WHERE active = 1 AND (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(last_run) > mins_interval * 60 OR last_run IS NULL)");
|
||||
$sth->execute();
|
||||
my $row;
|
||||
|
||||
while ($row = $sth->fetchrow_arrayref()) {
|
||||
|
||||
$id = @$row[0];
|
||||
$user1 = @$row[1];
|
||||
$user2 = @$row[2];
|
||||
$host1 = @$row[3];
|
||||
$authmech1 = @$row[4];
|
||||
$password1 = @$row[5];
|
||||
$exclude = @$row[6];
|
||||
$port1 = @$row[7];
|
||||
$enc1 = @$row[8];
|
||||
$delete2duplicates = @$row[9];
|
||||
$maxage = @$row[10];
|
||||
$subfolder2 = @$row[11];
|
||||
|
||||
if ($enc1 eq "TLS") { $enc1 = "--tls1"; } elsif ($enc1 eq "SSL") { $enc1 = "--ssl1"; } else { undef $enc1; }
|
||||
|
||||
run [ "/usr/local/bin/imapsync",
|
||||
"--timeout1", "10",
|
||||
"--tmpdir", "/tmp",
|
||||
"--subscribeall",
|
||||
($exclude eq "" ? () : ("--exclude", $exclude)),
|
||||
($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)),
|
||||
($maxage eq "0" ? () : ('--maxage', $maxage)),
|
||||
($delete2duplicates ne "1" ? () : ('--delete2duplicates')),
|
||||
(!defined($enc1) ? () : ($enc1)),
|
||||
"--host1", $host1,
|
||||
"--user1", $user1,
|
||||
"--password1", $password1,
|
||||
"--port1", $port1,
|
||||
"--host2", "localhost",
|
||||
"--user2", $user2 . '*' . trim($master_user),
|
||||
"--password2", trim($master_pass),
|
||||
'--no-modulesversion'], ">", \my $stdout;
|
||||
|
||||
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, last_run = NOW() WHERE id = ?");
|
||||
$update->bind_param( 1, ${stdout} );
|
||||
$update->bind_param( 2, ${id} );
|
||||
$update->execute();
|
||||
}
|
||||
|
||||
$sth->finish();
|
||||
$dbh->disconnect();
|
||||
|
||||
$lockmgr->unlock($lock_file);
|
4
data/Dockerfiles/dovecot/postlogin.sh
Executable file
4
data/Dockerfiles/dovecot/postlogin.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
export MASTER_USER=$USER
|
||||
exec "$@"
|
21
data/Dockerfiles/dovecot/supervisord.conf
Normal file
21
data/Dockerfiles/dovecot/supervisord.conf
Normal file
@ -0,0 +1,21 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:syslog-ng]
|
||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||
redirect_stderr=true
|
||||
autostart=true
|
||||
stdout_syslog=true
|
||||
|
||||
[program:dovecot]
|
||||
command=/usr/sbin/dovecot -F
|
||||
autorestart=true
|
||||
|
||||
[program:logfiles]
|
||||
command=/usr/bin/tail -f /var/log/mail.log /var/log/syslog
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:cron]
|
||||
command=/usr/sbin/cron -f
|
||||
autorestart=true
|
@ -6,6 +6,11 @@ sed -i "/^user/c\user = ${DBUSER}" /opt/postfix/conf/sql/*
|
||||
sed -i "/^password/c\password = ${DBPASS}" /opt/postfix/conf/sql/*
|
||||
sed -i "/^dbname/c\dbname = ${DBNAME}" /opt/postfix/conf/sql/*
|
||||
|
||||
postfix -c /opt/postfix/conf start
|
||||
|
||||
sleep infinity
|
||||
postconf -c /opt/postfix/conf
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Postfix configuration error, refusing to start."
|
||||
exit 1
|
||||
else
|
||||
postfix -c /opt/postfix/conf start
|
||||
sleep infinity
|
||||
fi
|
||||
|
@ -11,7 +11,14 @@ RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends apt-transport-https ca-certificates wget syslog-ng syslog-ng-core supervisor mysql-client cron \
|
||||
&& apt-get install -y --no-install-recommends apt-transport-https \
|
||||
ca-certificates \
|
||||
wget \
|
||||
syslog-ng \
|
||||
syslog-ng-core \
|
||||
supervisor \
|
||||
mysql-client \
|
||||
cron \
|
||||
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
|
||||
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
|
||||
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc" \
|
||||
@ -35,8 +42,9 @@ RUN echo '0 0 * * * sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/s
|
||||
COPY ./reconf-domains.sh /
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
|
||||
EXPOSE 20000
|
||||
EXPOSE 9191
|
||||
#EXPOSE 20000
|
||||
#EXPOSE 9191
|
||||
#EXPOSE 9192
|
||||
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
|
@ -1,22 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wait for MySQL to warm-up
|
||||
while mysqladmin ping --host mysql --silent; do
|
||||
|
||||
# Recreate view
|
||||
|
||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
||||
|
||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, senderacl, home) AS
|
||||
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), IFNULL(gs.send_as, ''), CONCAT('/var/vmail/', maildir) FROM mailbox
|
||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, senderacl, home, kind, multiple_bookings) AS
|
||||
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), IFNULL(gs.send_as, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox
|
||||
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
|
||||
LEFT OUTER JOIN grouped_sender_acl gs ON gs.username = mailbox.username
|
||||
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
||||
WHERE mailbox.active = '1';
|
||||
EOF
|
||||
|
||||
# Wait for MySQL to warm-up
|
||||
while ! mysqladmin ping --host mysql --silent; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
mkdir -p /var/lib/sogo/GNUstep/Defaults/
|
||||
|
||||
@ -69,8 +68,6 @@ while read line
|
||||
<string>kind</string>
|
||||
<key>MultipleBookingsFieldName</key>
|
||||
<string>multiple_bookings</string>
|
||||
<key>IMAPLoginFieldName</key>
|
||||
<string>c_uid</string>
|
||||
<key>canAuthenticate</key>
|
||||
<string>YES</string>
|
||||
<key>displayName</key>
|
||||
@ -99,4 +96,6 @@ echo ' </dict>
|
||||
chown sogo:sogo -R /var/lib/sogo/
|
||||
chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
|
||||
sleep infinite
|
||||
sleep 99999
|
||||
|
||||
done;
|
||||
|
@ -30,6 +30,12 @@ stdout_logfile_maxbytes=0
|
||||
command=/usr/sbin/cron -f
|
||||
autorestart=true
|
||||
|
||||
[program:sogo-webres]
|
||||
command=/usr/bin/python -u -m SimpleHTTPServer 9192
|
||||
directory=/usr/lib/GNUstep/SOGo/
|
||||
user=sogo
|
||||
autorestart=true
|
||||
|
||||
[inet_http_server]
|
||||
port=9191
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
auth_mechanisms = plain login
|
||||
#mail_debug = yes
|
||||
log_path = /dev/stdout
|
||||
log_path = /var/log/mail.log
|
||||
disable_plaintext_auth = yes
|
||||
# Uncomment on NFS share
|
||||
#mmap_disable = yes
|
||||
@ -21,6 +21,7 @@ ssl_dh_parameters_length = 2048
|
||||
log_timestamp = "%Y-%m-%d %H:%M:%S "
|
||||
recipient_delimiter = +
|
||||
auth_master_user_separator = *
|
||||
mail_prefetch_count = 30
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = /etc/dovecot/dovecot-master.passwd
|
||||
@ -182,6 +183,9 @@ service managesieve-login {
|
||||
process_min_avail = 2
|
||||
vsz_limit = 128M
|
||||
}
|
||||
service imap {
|
||||
executable = imap imap-postlogin
|
||||
}
|
||||
service managesieve {
|
||||
process_limit = 256
|
||||
}
|
||||
@ -236,3 +240,8 @@ remote 127.0.0.1 {
|
||||
}
|
||||
submission_host = postfix:588
|
||||
mail_max_userip_connections = 500
|
||||
service imap-postlogin {
|
||||
executable = script-login /usr/local/bin/postlogin.sh
|
||||
unix_listener imap-postlogin {
|
||||
}
|
||||
}
|
||||
|
1
data/conf/nginx/listen.template
Normal file
1
data/conf/nginx/listen.template
Normal file
@ -0,0 +1 @@
|
||||
listen ${HTTPS_PORT};
|
@ -1,5 +1,8 @@
|
||||
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
|
||||
server {
|
||||
listen 443;
|
||||
include /etc/nginx/conf.d/listen.active;
|
||||
charset utf-8;
|
||||
override_charset on;
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||
@ -72,7 +75,7 @@ server {
|
||||
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
||||
proxy_set_header x-webobjects-remote-host $remote_addr;
|
||||
proxy_set_header x-webobjects-server-name $server_name;
|
||||
proxy_set_header x-webobjects-server-url $scheme://$host;
|
||||
proxy_set_header x-webobjects-server-url $scheme://$host:$server_port;
|
||||
proxy_set_header x-webobjects-server-port $server_port;
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 100m;
|
||||
@ -86,7 +89,7 @@ server {
|
||||
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
||||
proxy_set_header x-webobjects-remote-host $remote_addr;
|
||||
proxy_set_header x-webobjects-server-name $server_name;
|
||||
proxy_set_header x-webobjects-server-url $scheme://$host;
|
||||
proxy_set_header x-webobjects-server-url $scheme://$host:$server_port;
|
||||
proxy_set_header x-webobjects-server-port $server_port;
|
||||
#proxy_connect_timeout 90;
|
||||
#proxy_send_timeout 90;
|
||||
@ -101,16 +104,32 @@ server {
|
||||
}
|
||||
|
||||
location /SOGo.woa/WebServerResources/ {
|
||||
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||
proxy_pass http://sogo:9192/WebServerResources/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache sogo;
|
||||
proxy_cache_valid 200 1d;
|
||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||
allow all;
|
||||
}
|
||||
|
||||
location /SOGo/WebServerResources/ {
|
||||
alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||
proxy_pass http://sogo:9192/WebServerResources/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache sogo;
|
||||
proxy_cache_valid 200 1d;
|
||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||
allow all;
|
||||
}
|
||||
|
||||
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
||||
alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
||||
proxy_pass http://sogo:9192/$1.SOGo/Resources/$2;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache sogo;
|
||||
proxy_cache_valid 200 1d;
|
||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||
#alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
<?php
|
||||
ini_set('error_reporting', 0);
|
||||
/*
|
||||
The match section performs AND operation on different matches: for example, if you have from and rcpt in the same rule,
|
||||
then the rule matches only when from AND rcpt match. For similar matches, the OR rule applies: if you have multiple rcpt matches,
|
||||
then any of these will trigger the rule. If a rule is triggered then no more rules are matched.
|
||||
*/
|
||||
ini_set('error_reporting', '0');
|
||||
|
||||
header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
|
||||
$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
@ -33,9 +35,9 @@ while ($row = array_shift($rows)) {
|
||||
$spamscore = $stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(`value`, '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
WHERE (`object`= :object OR `object`= :object_domain)
|
||||
AND (`option` = 'blacklist_from' OR `option` = 'whitelist_from')");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$stmt->execute(array(':object' => $row['object'], ':object_domain' => substr(strrchr($row['object'], "@"), 1)));
|
||||
$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
|
||||
?>
|
||||
@ -55,10 +57,13 @@ while ($row = array_shift($rows)) {
|
||||
WHERE `mailbox`.`username` = :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$rows_aliases_2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_aliases_2 = array_filter(array_shift($rows_aliases_2))) {
|
||||
array_filter($rows_aliases_2);
|
||||
while ($row_aliases_2 = array_shift($rows_aliases_2)) {
|
||||
if (!empty($row_aliases_2['aliases'])) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_2['aliases'];?>";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
@ -68,6 +73,7 @@ while ($row = array_shift($rows)) {
|
||||
"add header" = <?=$spamscore['lowspamlevel'][0];?>;
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
@ -81,7 +87,6 @@ while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
whitelist_<?=$username_sane;?> {
|
||||
priority = high;
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(`value`, '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
@ -94,26 +99,30 @@ while ($row = array_shift($rows)) {
|
||||
<?php
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
rcpt = "/.*@<?=$username_userpref['username'];?>/";
|
||||
priority = medium;
|
||||
rcpt = "/.*@<?=$row['object'];?>/";
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
|
||||
WHERE `target_domain` = :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$rows_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($rows_domain_aliases);
|
||||
while ($row_domain_aliases = array_shift($rows_domain_aliases)) {
|
||||
?>
|
||||
rcpt = "<?=$row_domain_aliases['alias_domain'];?>";
|
||||
rcpt = "/.*@<?=$row_domain_aliases['alias_domain'];?>/";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = high;
|
||||
rcpt = "<?=$row['object'];?>";
|
||||
<?php
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` = :object_goto AND `address` NOT LIKE '@%' AND `address` != :object_address");
|
||||
$stmt->execute(array(':object_goto' => $row['object'], ':object_address' => $row['object']));
|
||||
$rows_aliases_wl_1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($rows_aliases_wl_1);
|
||||
while ($row_aliases_wl_1 = array_shift($rows_aliases_wl_1)) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_wl_1['address'];?>";
|
||||
@ -124,10 +133,13 @@ while ($row = array_shift($rows)) {
|
||||
WHERE `mailbox`.`username` = :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$rows_aliases_wl_2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_aliases_wl_2 = array_filter(array_shift($rows_aliases_wl_2))) {
|
||||
array_filter($rows_aliases_wl_2);
|
||||
while ($row_aliases_wl_2 = array_shift($rows_aliases_wl_2)) {
|
||||
if (!empty($row_aliases_wl_2['aliases'])) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_wl_2['aliases'];?>";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
@ -147,7 +159,6 @@ while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
blacklist_<?=$username_sane;?> {
|
||||
priority = medium;
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(`value`, '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
@ -160,40 +171,47 @@ while ($row = array_shift($rows)) {
|
||||
<?php
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
rcpt = "/.*@<?=$username_userpref['username'];?>/";
|
||||
priority = medium;
|
||||
rcpt = "/.*@<?=$row['object'];?>/";
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
|
||||
WHERE `target_domain` = :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$rows_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($rows_domain_aliases);
|
||||
while ($row_domain_aliases = array_shift($rows_domain_aliases)) {
|
||||
?>
|
||||
rcpt = "<?=$row_domain_aliases['alias_domain'];?>";
|
||||
rcpt = "/.*@<?=$row_domain_aliases['alias_domain'];?>/";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = high;
|
||||
rcpt = "<?=$row['object'];?>";
|
||||
<?php
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` = :object_goto AND `address` NOT LIKE '@%' AND `address` != :object_address");
|
||||
$stmt->execute(array(':object_goto' => $row['object'], ':object_address' => $row['object']));
|
||||
$rows_aliases_wl_1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_aliases_wl_1 = array_shift($rows_aliases_wl_1)) {
|
||||
$rows_aliases_bl_1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($rows_aliases_bl_1);
|
||||
while ($row_aliases_bl_1 = array_shift($rows_aliases_bl_1)) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_wl_1['address'];?>";
|
||||
rcpt = "<?=$row_aliases_bl_1['address'];?>";
|
||||
<?php
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `aliases` FROM `mailbox`
|
||||
LEFT OUTER JOIN `alias_domain` on `mailbox`.`domain` = `alias_domain`.`target_domain`
|
||||
WHERE `mailbox`.`username` = :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$rows_aliases_wl_2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_aliases_wl_2 = array_filter(array_shift($rows_aliases_wl_2))) {
|
||||
$rows_aliases_bl_2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($rows_aliases_bl_2);
|
||||
while ($row_aliases_bl_2 = array_shift($rows_aliases_bl_2)) {
|
||||
if (!empty($row_aliases_bl_2['aliases'])) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_wl_2['aliases'];?>";
|
||||
rcpt = "<?=$row_aliases_bl_2['aliases'];?>";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
@ -203,4 +221,4 @@ while ($row = array_shift($rows)) {
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
}
|
||||
}
|
204
data/web/add.php
204
data/web/add.php
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
@ -77,7 +77,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="adddomain" class="btn btn-success"><?=$lang['add']['save'];?></button>
|
||||
<button type="submit" name="mailbox_add_domain" class="btn btn-success"><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="glyphicon glyphicon-exclamation-sign text-danger"></span> <?=$lang['add']['restart_sogo_hint'];?></p>
|
||||
@ -112,7 +112,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="addalias" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
<button type="submit" name="mailbox_add_alias" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -132,29 +132,12 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="target_domain"><?=$lang['add']['target_domain'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select name="target_domain" id="target_domain" title="<?=$lang['add']['select'];?>">
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
||||
WHERE `domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :username
|
||||
AND `active`='1'
|
||||
)
|
||||
OR 'admin' = :admin");
|
||||
$stmt->execute(array(':username' => $_SESSION['mailcow_cc_username'], ':admin' => $_SESSION['mailcow_cc_role']));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row = array_shift($rows)) {
|
||||
echo "<option>".htmlspecialchars($row['domain'])."</option>";
|
||||
}
|
||||
?>
|
||||
<select name="target_domain" id="target_domain" title="<?=$lang['add']['select'];?>" required>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
echo "<option>".htmlspecialchars($domain)."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -167,7 +150,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="addaliasdomain" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
<button type="submit" name="mailbox_add_alias_domain" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -188,30 +171,13 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="col-sm-10">
|
||||
<select id="addSelectDomain" name="domain" id="domain" title="<?=$lang['add']['select'];?>" required>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
||||
WHERE `domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :username
|
||||
AND `active`='1'
|
||||
)
|
||||
OR 'admin' = :admin");
|
||||
$stmt->execute(array(':username' => $_SESSION['mailcow_cc_username'], ':admin' => $_SESSION['mailcow_cc_role']));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row = array_shift($rows)) {
|
||||
echo "<option>".htmlspecialchars($row['domain'])."</option>";
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
echo "<option>".htmlspecialchars($domain)."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name"><?=$lang['add']['full_name'];?></label>
|
||||
<div class="col-sm-10">
|
||||
@ -247,7 +213,61 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="addmailbox" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
<button type="submit" name="mailbox_add_mailbox" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
elseif (isset($_GET['resource'])) {
|
||||
?>
|
||||
<h4><?=$lang['add']['resource'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="description" id="description" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="domain" id="domain" title="<?=$lang['add']['select'];?>" required>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
echo "<option>".htmlspecialchars($domain)."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['kind'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="kind" id="kind" title="<?=$lang['add']['select'];?>" required>
|
||||
<option value="location">Location</option>
|
||||
<option value="group">Group</option>
|
||||
<option value="thing">Thing</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" checked> <?=$lang['add']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="multiple_bookings" checked> <?=$lang['add']['multiple_bookings'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="mailbox_add_resource" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -259,6 +279,94 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user")) {
|
||||
if (isset($_GET['syncjob'])) {
|
||||
?>
|
||||
<h4><?=$lang['add']['syncjob'];?></h4>
|
||||
<p><?=$lang['add']['syncjob_hint'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="host1"><?=$lang['add']['hostname'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="host1" id="host1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="port1">Port</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="port1" id="port1" min="1" max="65535" value="143" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="user1"><?=$lang['add']['username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="user1" id="user1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password1"><?=$lang['add']['password'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="password1" id="password1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="enc1"><?=$lang['add']['enc_method'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select name="enc1" id="enc1" title="<?=$lang['add']['select'];?>" required>
|
||||
<option selected>TLS</option>
|
||||
<option>SSL</option>
|
||||
<option>PLAIN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['add']['mins_interval'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="mins_interval" min="10" max="3600" value="20" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="subfolder2"><?=$lang['edit']['subfolder2'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="subfolder2" id="subfolder2" value="External">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="maxage" id="maxage" min="0" max="32000" value="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="exclude" id="exclude" value="(?i)spam|(?i)junk">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="delete2duplicates" checked> <?=$lang['add']['delete2duplicates'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" checked> <?=$lang['add']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="add_syncjob" value="1" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-danger" role="alert"><?=$lang['danger']['access_denied'];?></div>
|
||||
|
@ -6,249 +6,284 @@ require_once("inc/header.inc.php");
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
?>
|
||||
<div class="container">
|
||||
<h4><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?=$lang['admin']['access'];?></h4>
|
||||
<h4><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?=$lang['admin']['access'];?></h4>
|
||||
|
||||
<div class="panel-group" id="accordion_access">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading"><?=$lang['admin']['admin_details'];?></div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `admin`
|
||||
WHERE `superadmin`='1' and active='1'");
|
||||
$stmt->execute();
|
||||
$AdminData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
?>
|
||||
<input type="hidden" name="admin_user_now" value="<?=htmlspecialchars($AdminData['username']);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="admin_user"><?=$lang['admin']['admin'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="admin_user" id="admin_user" value="<?=htmlspecialchars($AdminData['username']);?>" required>
|
||||
↳ <kbd>a-z A-Z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="admin_pass"><?=$lang['admin']['password'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="admin_pass" id="admin_pass" placeholder="<?=$lang['admin']['unchanged_if_empty'];?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="admin_pass2"><?=$lang['admin']['password_repeat'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="admin_pass2" id="admin_pass2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_set_admin" class="btn btn-default"><?=$lang['admin']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div style="cursor:pointer;" class="panel-heading" data-toggle="collapse" data-parent="#accordion_access" data-target="#collapseDomAdmins">
|
||||
<span class="accordion-toggle"><?=$lang['admin']['domain_admins'];?></span>
|
||||
</div>
|
||||
<div id="collapseDomAdmins" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<form method="post">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainadminstable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 100px;"><?=$lang['admin']['username'];?></th>
|
||||
<th class="sort-table" style="min-width: 166px;"><?=$lang['admin']['admin_domains'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['admin']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['admin']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT DISTINCT
|
||||
`username`,
|
||||
CASE WHEN `active`='1' THEN '".$lang['admin']['yes']."' ELSE '".$lang['admin']['no']."' END AS `active`
|
||||
FROM `domain_admins`
|
||||
WHERE `username` IN (
|
||||
SELECT `username` FROM `admin`
|
||||
WHERE `superadmin`!='1'
|
||||
)");
|
||||
$rows_username = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if(!empty($rows_username)):
|
||||
while ($row_user_state = array_shift($rows_username)):
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars(strtolower($row_user_state['username']));?></td>
|
||||
<td>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain_admins` WHERE `username` = :username");
|
||||
$stmt->execute(array('username' => $row_user_state['username']));
|
||||
$rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row_domain = array_shift($rows_domain)) {
|
||||
echo htmlspecialchars($row_domain['domain']).'<br />';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?=$row_user_state['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="edit.php?domainadmin=<?=$row_user_state['username'];?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['admin']['edit'];?></a>
|
||||
<a href="delete.php?domainadmin=<?=$row_user_state['username'];?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="panel-group" id="accordion_access">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading"><?=$lang['admin']['admin_details'];?></div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
||||
<?php $admindetails = get_admin_details(); ?>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="admin_user"><?=$lang['admin']['admin'];?>:</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="admin_user" id="admin_user" value="<?=htmlspecialchars($admindetails['username']);?>" required>
|
||||
↳ <kbd>a-z A-Z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="admin_pass"><?=$lang['admin']['password'];?>:</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" name="admin_pass" id="admin_pass" placeholder="<?=$lang['admin']['unchanged_if_empty'];?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="admin_pass2"><?=$lang['admin']['password_repeat'];?>:</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" name="admin_pass2" id="admin_pass2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<button type="submit" name="edit_admin_account" class="btn btn-default"><?=$lang['admin']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?>:</div>
|
||||
<div class="col-sm-9 col-xs-7">
|
||||
<p><?=get_tfa()['pretty'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<select data-width="auto" id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
||||
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
||||
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
|
||||
<option value="none"><?=$lang['tfa']['none'];?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div style="cursor:pointer;" class="panel-heading" data-toggle="collapse" data-parent="#accordion_access" data-target="#collapseDomAdmins">
|
||||
<span class="accordion-toggle"><?=$lang['admin']['domain_admins'];?></span>
|
||||
</div>
|
||||
<div id="collapseDomAdmins" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<form method="post">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainadminstable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 100px;"><?=$lang['admin']['username'];?></th>
|
||||
<th class="sort-table" style="min-width: 166px;"><?=$lang['admin']['admin_domains'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['admin']['active'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['tfa']['tfa'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['admin']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach (get_domain_admins() as $domain_admin) {
|
||||
$da_data = get_domain_admin_details($domain_admin);
|
||||
if (!empty($da_data)):
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars(strtolower($domain_admin));?></td>
|
||||
<td>
|
||||
<?php
|
||||
foreach ($da_data['selected_domains'] as $domain) {
|
||||
echo htmlspecialchars($domain).'<br />';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?=$da_data['active'];?></td>
|
||||
<td><?=empty($da_data['tfa_active_int']) ? "✘" : "✔";?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="edit.php?domainadmin=<?=$domain_admin;?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['admin']['edit'];?></a>
|
||||
<a href="delete.php?domainadmin=<?=$domain_admin;?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="4" style="text-align: center; font-style: italic;"><?=$lang['admin']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
<small>
|
||||
<legend><?=$lang['admin']['add_domain_admin'];?></legend>
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="username"><?=$lang['admin']['username'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="username" id="username" required>
|
||||
↳ <kbd>a-z A-Z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name"><?=$lang['admin']['admin_domains'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select title="<?=$lang['admin']['search_domain_da'];?>" style="width:100%" name="domain[]" size="5" multiple>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT domain FROM domain");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row = array_shift($rows)) {
|
||||
echo "<option>".htmlspecialchars($row['domain'])."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password"><?=$lang['admin']['password'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password" id="password" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password2"><?=$lang['admin']['password_repeat'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password2" id="password2" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" checked> <?=$lang['admin']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_add_domain_admin" class="btn btn-default"><?=$lang['admin']['add'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> <?=$lang['admin']['configuration'];?></h4>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
|
||||
<div id="collapseDKIM" class="panel-collapse">
|
||||
<div class="panel-body">
|
||||
<?php
|
||||
$dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
|
||||
$dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
|
||||
foreach($dnstxt_files as $file) {
|
||||
$pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
|
||||
$domain = substr($file, 0, -5);
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong> (dkim._domainkey)</p>
|
||||
</div>
|
||||
<div class="col-xs-9">
|
||||
<pre>v=DKIM1;k=rsa;t=s;s=email;p=<?=$pubKey;?></pre>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove-circle"></span></a>
|
||||
<input type="hidden" name="delete_dkim_record" value="<?=htmlspecialchars($file);?>">
|
||||
<input type="hidden" name="dkim[domain]" value="<?=$domain;?>">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<legend><?=$lang['admin']['dkim_add_key'];?></legend>
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<label for="dkim_domain">Domain</label>
|
||||
<input class="form-control" id="dkim_domain" name="dkim[domain]" placeholder="example.org" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select class="form-control" id="dkim_key_size" name="dkim[key_size]" title="<?=$lang['admin']['dkim_key_length'];?>" required>
|
||||
<option>1024</option>
|
||||
<option>2048</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" name="add_dkim_record" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="4" style="text-align: center; font-style: italic;"><?=$lang['admin']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
<small>
|
||||
<legend><?=$lang['admin']['add_domain_admin'];?></legend>
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="username"><?=$lang['admin']['username'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="username" id="username" required>
|
||||
↳ <kbd>a-z A-Z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name"><?=$lang['admin']['admin_domains'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select title="<?=$lang['admin']['search_domain_da'];?>" style="width:100%" name="domain[]" size="5" multiple>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
echo "<option>".htmlspecialchars($domain)."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password"><?=$lang['admin']['password'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password" id="password" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password2"><?=$lang['admin']['password_repeat'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password2" id="password2" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" checked> <?=$lang['admin']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="add_domain_admin" class="btn btn-default"><?=$lang['admin']['add'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> <?=$lang['admin']['configuration'];?></h4>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
|
||||
<div id="collapseDKIM" class="panel-collapse">
|
||||
<div class="panel-body">
|
||||
<p style="margin-bottom:40px"><?=$lang['admin']['dkim_key_hint'];?></p>
|
||||
<?php
|
||||
foreach(mailbox_get_domains() as $domain) {
|
||||
if (!empty($dkim = dkim_get_key_details($domain))) {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br />
|
||||
<span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span>
|
||||
<span class="label label-info"><?=$dkim['length'];?> bit</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-8">
|
||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" method="post">
|
||||
<input type="hidden" name="domain" value="<?=$domain;?>">
|
||||
<input type="hidden" name="dkim_delete_key" value="1">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="top" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br /><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||
</div>
|
||||
<div class="col-xs-8"><pre>-</pre></div>
|
||||
<div class="col-xs-1"> </div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
foreach(mailbox_get_alias_domains($domain) as $alias_domain) {
|
||||
if (!empty($dkim = dkim_get_key_details($alias_domain))) {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-offset-1 col-xs-2">
|
||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small>
|
||||
<span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span>
|
||||
<span class="label label-info"><?=$dkim['length'];?> bit</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-8">
|
||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" method="post">
|
||||
<input type="hidden" name="domain" value="<?=$alias_domain;?>">
|
||||
<input type="hidden" name="dkim_delete_key" value="1">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="top" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-2 col-xs-offset-1">
|
||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||
</div>
|
||||
<div class="col-xs-8"><pre>-</pre></div>
|
||||
<div class="col-xs-1"> </div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach(dkim_get_blind_keys() as $blind) {
|
||||
if (!empty($dkim = dkim_get_key_details($blind))) {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<p>Domain: <strong><?=htmlspecialchars($blind);?></strong><br /><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
||||
</div>
|
||||
<div class="col-xs-8">
|
||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" method="post">
|
||||
<input type="hidden" name="domain" value="<?=$blind;?>">
|
||||
<input type="hidden" name="dkim_delete_key" value="1">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="top" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<legend style="margin-top:40px"><?=$lang['admin']['dkim_add_key'];?></legend>
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<label for="domain">Domain</label>
|
||||
<input class="form-control" id="domain" name="domain" placeholder="example.org" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select data-width="200px" class="form-control" id="key_size" name="key_size" title="<?=$lang['admin']['dkim_key_length'];?>" required>
|
||||
<option data-subtext="bits">1024</option>
|
||||
<option data-subtext="bits">2048</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" name="dkim_add_key" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js" integrity="sha384-YWP9O4NjmcGo4oEJFXvvYSEzuHIvey+LbXkBNJ1Kd0yfugEZN9NCQNpRYBVC1RvA" crossorigin="anonymous"></script>
|
||||
<script src="js/sorttable.js"></script>
|
||||
<script src="js/admin.js"></script>
|
||||
|
19
data/web/css/mailbox.css
Normal file
19
data/web/css/mailbox.css
Normal file
@ -0,0 +1,19 @@
|
||||
.panel-heading div {
|
||||
margin-top: -18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.panel-heading div span {
|
||||
margin-left:5px;
|
||||
}
|
||||
.panel-body {
|
||||
display: none;
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.progress {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.table>thead>tr>th {
|
||||
vertical-align: top !important;
|
||||
}
|
46
data/web/css/mailcow.css
Normal file
46
data/web/css/mailcow.css
Normal file
@ -0,0 +1,46 @@
|
||||
#maxmsgsize { min-width: 80px; }
|
||||
#slider1 .slider-selection {
|
||||
background: #FFD700;
|
||||
}
|
||||
#slider1 .slider-track-high {
|
||||
background: #FF4500;
|
||||
}
|
||||
#slider1 .slider-track-low {
|
||||
background: #66CD00;
|
||||
}
|
||||
.striped:nth-child(odd) {
|
||||
background-color: #fff;
|
||||
}
|
||||
.striped:nth-child(even) {
|
||||
background-color: #fafafa;
|
||||
border:1px solid white;
|
||||
}
|
||||
.btn {
|
||||
text-transform: none;
|
||||
}
|
||||
.glyphicon-spin {
|
||||
font-size:12px;
|
||||
-webkit-animation: spin 2000ms infinite linear;
|
||||
animation: spin 2000ms infinite linear;
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
79
data/web/css/tables.css
Normal file
79
data/web/css/tables.css
Normal file
@ -0,0 +1,79 @@
|
||||
ul[id*="sortable"] { word-wrap: break-word; list-style-type: none; float: left; padding: 0 15px 0 0; width: 48%; cursor:move}
|
||||
ul[id$="sortable-active"] li {cursor:move; }
|
||||
ul[id$="sortable-inactive"] li {cursor:move }
|
||||
.list-heading { cursor:default !important}
|
||||
.ui-state-disabled { cursor:no-drop; color:#ccc; }
|
||||
.ui-state-highlight {background: #F5F5F5 !important; height: 41px !important; cursor:move }
|
||||
table[data-sortable] {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
table[data-sortable] th {
|
||||
vertical-align: bottom;
|
||||
font-weight: bold;
|
||||
}
|
||||
table[data-sortable] th, table[data-sortable] td {
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
}
|
||||
table[data-sortable] th:not([data-sortable="false"]) {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-touch-callout: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
table[data-sortable] th:after {
|
||||
content: "";
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
vertical-align: inherit;
|
||||
height: 0;
|
||||
width: 0;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
margin-right: 1px;
|
||||
margin-left: 10px;
|
||||
float: right;
|
||||
}
|
||||
table[data-sortable] th[data-sortable="false"]:after {
|
||||
display: none;
|
||||
}
|
||||
table[data-sortable] th[data-sorted="true"]:after {
|
||||
visibility: visible;
|
||||
}
|
||||
table[data-sortable] th[data-sorted-direction="descending"]:after {
|
||||
border-top-color: inherit;
|
||||
margin-top: 8px;
|
||||
}
|
||||
table[data-sortable] th[data-sorted-direction="ascending"]:after {
|
||||
border-bottom-color: inherit;
|
||||
margin-top: 3px;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap thead th {
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"] {
|
||||
color: #3a87ad;
|
||||
background: #d9edf7;
|
||||
border-bottom-color: #bce8f1;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="descending"]:after {
|
||||
border-top-color: #3a87ad;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="ascending"]:after {
|
||||
border-bottom-color: #3a87ad;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped tbody > tr:nth-child(odd) > td {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
#data td, #no-data td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.sort-table:hover {
|
||||
border-bottom-color: #00B7DC !important;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
@ -30,7 +30,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<input type="hidden" name="domain" value="<?php echo htmlspecialchars($domain) ?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="deletedomain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
<button type="submit" name="mailbox_delete_domain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -49,7 +49,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<input type="hidden" name="address" value="<?php echo htmlspecialchars($_GET["alias"]) ?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="deletealias" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
<button type="submit" name="mailbox_delete_alias" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -66,27 +66,16 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
isset($_GET["aliasdomain"]) &&
|
||||
is_valid_domain_name($_GET["aliasdomain"]) &&
|
||||
!empty($_GET["aliasdomain"])) {
|
||||
$alias_domain = strtolower(trim($_GET["aliasdomain"]));
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
|
||||
WHERE `alias_domain`= :alias_domain");
|
||||
$stmt->execute(array(':alias_domain' => $alias_domain));
|
||||
$DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
|
||||
$alias_domain = $_GET["aliasdomain"];
|
||||
$result = mailbox_get_alias_domain_details($alias_domain);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_domainalias_warning'], htmlspecialchars($_GET["aliasdomain"]));?></div>
|
||||
<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
|
||||
<input type="hidden" name="alias_domain" value="<?php echo htmlspecialchars($alias_domain) ?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="deletealiasdomain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
<button type="submit" name="mailbox_delete_alias_domain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -102,7 +91,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
elseif (isset($_GET["domainadmin"]) &&
|
||||
ctype_alnum(str_replace(array('_', '.', '-'), '', $_GET["domainadmin"])) &&
|
||||
!empty($_GET["domainadmin"]) &&
|
||||
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$domain_admin = $_GET["domainadmin"];
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_domainadmin_warning'], htmlspecialchars($_GET["domainadmin"]));?></div>
|
||||
@ -110,7 +99,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($domain_admin);?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="trigger_delete_domain_admin" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
<button type="submit" name="delete_domain_admin" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -121,16 +110,74 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) &&
|
||||
!empty($_GET["mailbox"])) {
|
||||
$mailbox = $_GET["mailbox"];
|
||||
$domain = substr(strrchr($mailbox, "@"), 1);
|
||||
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
|
||||
if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailbox)) {
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_mailbox_warning'], htmlspecialchars($_GET["mailbox"]));?></div>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_mailbox_warning'], htmlspecialchars($mailbox));?></div>
|
||||
<p><?=$lang['delete']['remove_mailbox_details'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($mailbox);?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="deletemailbox" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
<button type="submit" name="mailbox_delete_mailbox" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
// DELETE RESOURCE
|
||||
elseif (isset($_GET["resource"]) &&
|
||||
filter_var($_GET["resource"], FILTER_VALIDATE_EMAIL) &&
|
||||
!empty($_GET["resource"])) {
|
||||
$resource = $_GET["resource"];
|
||||
if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resource)) {
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_resource_warning'], htmlspecialchars($resource));?></div>
|
||||
<p><?=$lang['delete']['remove_resource_details'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
|
||||
<input type="hidden" name="name" value="<?=htmlspecialchars($resource);?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<button type="submit" name="mailbox_delete_resource" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user")) {
|
||||
// DELETE SYNCJOB
|
||||
if (isset($_GET["syncjob"]) &&
|
||||
is_numeric($_GET["syncjob"]) &&
|
||||
filter_var($_SESSION['mailcow_cc_username'], FILTER_VALIDATE_EMAIL)) {
|
||||
$id = $_GET["syncjob"];
|
||||
$result = get_syncjob_details($id);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_syncjob_warning'], htmlspecialchars($result['user2']));?></div>
|
||||
<p><?=$lang['delete']['remove_syncjob_details'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="/user.php">
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($mailbox);?>">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<input type="hidden" name="id" value="<?=$_GET["syncjob"];?>">
|
||||
<button type="submit" name="delete_syncjob" value="1" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
@ -20,34 +20,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
if (isset($_GET["alias"]) &&
|
||||
!empty($_GET["alias"])) {
|
||||
$alias = $_GET["alias"];
|
||||
$domain = substr(strrchr($alias, "@"), 1);
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `alias`
|
||||
WHERE `address`= :address
|
||||
AND `goto` != :goto
|
||||
AND (
|
||||
`domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `active`='1'
|
||||
AND `username`= :username
|
||||
)
|
||||
OR 'admin'= :admin
|
||||
)");
|
||||
$stmt->execute(array(
|
||||
':address' => $alias,
|
||||
':goto' => $alias,
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role']
|
||||
));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if ($result !== false) {
|
||||
$result = mailbox_get_alias_details($alias);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['alias'];?></h4>
|
||||
<br />
|
||||
@ -62,13 +36,13 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
|
||||
<label><input type="checkbox" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="editalias" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
<button type="submit" name="mailbox_edit_alias" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -86,68 +60,34 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
$_GET["domainadmin"] != 'admin' &&
|
||||
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$domain_admin = $_GET["domainadmin"];
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `domain_admins` WHERE `username`= :domain_admin");
|
||||
$stmt->execute(array(
|
||||
':domain_admin' => $domain_admin
|
||||
));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if ($result !== false) {
|
||||
$result = get_domain_admin_details($domain_admin);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['domain_admin'];?></h4>
|
||||
<br />
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($domain_admin);?>">
|
||||
<input type="hidden" name="username_now" value="<?=htmlspecialchars($domain_admin);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="username"><?=$lang['edit']['username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" type="text" name="username" value="<?=htmlspecialchars($domain_admin);?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['domains'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select id="domain" name="domain[]" multiple>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
||||
WHERE `domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :domain_admin)");
|
||||
$stmt->execute(array(':domain_admin' => $domain_admin));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row_selected = array_shift($rows)):
|
||||
foreach ($result['selected_domains'] as $domain):
|
||||
?>
|
||||
<option selected><?=htmlspecialchars($row_selected['domain']);?></option>
|
||||
<option selected><?=htmlspecialchars($domain);?></option>
|
||||
<?php
|
||||
endwhile;
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
||||
WHERE `domain` NOT IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :domain_admin)");
|
||||
$stmt->execute(array(':domain_admin' => $domain_admin));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
while ($row_unselected = array_shift($rows)):
|
||||
endforeach;
|
||||
foreach ($result['unselected_domains'] as $domain):
|
||||
?>
|
||||
<option><?=htmlspecialchars($row_unselected['domain']);?></option>
|
||||
<option><?=htmlspecialchars($domain);?></option>
|
||||
<?php
|
||||
endwhile;
|
||||
endforeach;
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
@ -167,13 +107,20 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
|
||||
<label><input type="checkbox" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_edit_domain_admin" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="delete_tfa"> <?=$lang['tfa']['delete_tfa'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="edit_domain_admin" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -189,29 +136,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
is_valid_domain_name($_GET["domain"]) &&
|
||||
!empty($_GET["domain"])) {
|
||||
$domain = $_GET["domain"];
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `domain` WHERE `domain`='".$domain."'
|
||||
AND (
|
||||
`domain` IN (
|
||||
SELECT `domain` from `domain_admins`
|
||||
WHERE `active`='1'
|
||||
AND `username` = :username
|
||||
)
|
||||
OR 'admin'= :admin
|
||||
)");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role']
|
||||
));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if ($result !== false) {
|
||||
$result = mailbox_get_domain_details($domain);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['domain'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
@ -228,34 +154,34 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="aliases"><?=$lang['edit']['max_aliases'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="aliases" id="aliases" value="<?=intval($result['aliases']);?>">
|
||||
<input type="number" class="form-control" name="aliases" id="aliases" value="<?=intval($result['max_num_aliases_for_domain']);?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="mailboxes"><?=$lang['edit']['max_mailboxes'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="mailboxes" id="mailboxes" value="<?=intval($result['mailboxes']);?>">
|
||||
<input type="number" class="form-control" name="mailboxes" id="mailboxes" value="<?=intval($result['max_num_mboxes_for_domain']);?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="maxquota"><?=$lang['edit']['max_quota'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="maxquota" id="maxquota" value="<?=intval($result['maxquota']);?>">
|
||||
<input type="number" class="form-control" name="maxquota" id="maxquota" value="<?=intval($result['max_new_mailbox_quota'] / 1048576);?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['domain_quota'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="quota" id="quota" value="<?=intval($result['quota']);?>">
|
||||
<input type="number" class="form-control" name="quota" id="quota" value="<?=intval($result['max_quota_for_domain'] / 1048576);?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2"><?=$lang['edit']['backup_mx_options'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="backupmx" <?php if (isset($result['backupmx']) && $result['backupmx']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['relay_domain'];?></label>
|
||||
<label><input type="checkbox" name="backupmx" <?=(isset($result['backupmx_int']) && $result['backupmx_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_domain'];?></label>
|
||||
<br />
|
||||
<label><input type="checkbox" name="relay_all_recipients" <?php if (isset($result['relay_all_recipients']) && $result['relay_all_recipients']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['relay_all'];?></label>
|
||||
<label><input type="checkbox" name="relay_all_recipients" <?=(isset($result['relay_all_recipients']) && $result['relay_all_recipients']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_all'];?></label>
|
||||
<p><?=$lang['edit']['relay_all_info'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -266,37 +192,148 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked "; }; if ($_SESSION['mailcow_cc_role']=="domainadmin") { echo "disabled"; }; ?>> <?=$lang['edit']['active'];?></label>
|
||||
<label><input type="checkbox" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ? "checked" : null;?> <?=($_SESSION['mailcow_cc_role'] == "admin") ? null : "disabled";?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="editdomain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
<button type="submit" name="mailbox_edit_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
if (file_exists($GLOBALS["MC_DKIM_TXTS"]. "/" . $domain . "." . "dkim")) {
|
||||
$pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]. "/" . $domain . "." . "dkim");
|
||||
if (!empty($dkim = dkim_get_key_details($domain))) {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong> (dkim._domainkey)</p>
|
||||
</div>
|
||||
<div class="col-xs-9">
|
||||
<pre>v=DKIM1;k=rsa;t=s;s=email;p=<?=$pubKey;?></pre>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove-circle"></span></a>
|
||||
<input type="hidden" name="delete_dkim_record" value="<?=htmlspecialchars($file);?>">
|
||||
<input type="hidden" name="dkim[domain]" value="<?=$domain;?>">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (dkim._domainkey)</p>
|
||||
</div>
|
||||
<div class="col-xs-10">
|
||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h4><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> <?=$lang['user']['spamfilter_wl'];?></h4>
|
||||
<p><?=$lang['user']['spamfilter_wl_desc'];?></p>
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
|
||||
</div>
|
||||
<?php
|
||||
$get_policy_list = get_policy_list($domain);
|
||||
if (empty($get_policy_list['whitelist'])):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
|
||||
</div>
|
||||
<?php
|
||||
else:
|
||||
foreach($get_policy_list['whitelist'] as $wl):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$wl['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<?php
|
||||
if ($wl['object'] == $domain):
|
||||
?>
|
||||
<input type="hidden" name="delete_prefid" value="<?=$wl['prefid'];?>">
|
||||
<input type="hidden" name="delete_policy_list_item">
|
||||
<input type="hidden" name="domain" value="<?=$domain;?>">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
<hr style="margin:5px 0px 7px 0px">
|
||||
<div class="row">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6">
|
||||
<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
|
||||
<input type="hidden" name="object_list" value="wl">
|
||||
<input type="hidden" name="domain" value="<?=$domain;?>">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<h4><span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"></span> <?=$lang['user']['spamfilter_bl'];?></h4>
|
||||
<p><?=$lang['user']['spamfilter_bl_desc'];?></p>
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
|
||||
</div>
|
||||
<?php
|
||||
if (empty($get_policy_list['blacklist'])):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
|
||||
</div>
|
||||
<?php
|
||||
else:
|
||||
foreach($get_policy_list['blacklist'] as $bl):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$bl['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<input type="hidden" name="delete_prefid" value="<?=$bl['prefid'];?>">
|
||||
<?php
|
||||
if ($bl['object'] == $domain):
|
||||
?>
|
||||
<input type="hidden" name="delete_policy_list_item">
|
||||
<input type="hidden" name="domain" value="<?=$domain;?>">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
<hr style="margin:5px 0px 7px 0px">
|
||||
<div class="row">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6">
|
||||
<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
|
||||
<input type="hidden" name="object_list" value="bl">
|
||||
<input type="hidden" name="domain" value="<?=$domain;?>">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
@ -308,31 +345,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
is_valid_domain_name($_GET["aliasdomain"]) &&
|
||||
!empty($_GET["aliasdomain"])) {
|
||||
$alias_domain = $_GET["aliasdomain"];
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `alias_domain`
|
||||
WHERE `alias_domain`= :alias_domain
|
||||
AND (
|
||||
`target_domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `active`='1'
|
||||
AND `username`= :username
|
||||
)
|
||||
OR 'admin'= :admin
|
||||
)");
|
||||
$stmt->execute(array(
|
||||
':alias_domain' => $alias_domain,
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role']
|
||||
));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if ($result !== false) {
|
||||
$result = mailbox_get_alias_domain_details($alias_domain);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['edit_alias_domain'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
@ -346,46 +360,29 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?= (isset($result['active']) && $result['active']=="1") ? "checked" : null ?>> <?=$lang['edit']['active'];?></label>
|
||||
<label><input type="checkbox" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ? "checked" : null ?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="editaliasdomain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
<button type="submit" name="mailbox_edit_alias_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
$dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
|
||||
$dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
|
||||
foreach($dnstxt_files as $file) {
|
||||
if (explode("_", $file)[1] == $domain) {
|
||||
$str = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
|
||||
$str = preg_replace('/\r|\t|\n/', '', $str);
|
||||
preg_match('/\(.*\)/im', $str, $matches);
|
||||
if(isset($matches[0])) {
|
||||
$str = str_replace(array(' ', '"', '(', ')'), '', $matches[0]);
|
||||
}
|
||||
if (!empty($dkim = dkim_get_key_details($alias_domain))) {
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<p class="text-right"><?=$lang['edit']['dkim_signature'];?></p>
|
||||
</div>
|
||||
<div class="col-xs-10">
|
||||
<div class="col-md-2"><b><?=$lang['edit']['dkim_txt_name'];?></b></div>
|
||||
<div class="col-md-10">
|
||||
<pre><?=htmlspecialchars(explode("_", $file)[0]);?>._domainkey</pre>
|
||||
</div>
|
||||
<div class="col-md-2"><b><?=$lang['edit']['dkim_txt_value'];?></b></div>
|
||||
<div class="col-md-10">
|
||||
<pre><?=htmlspecialchars($str);?></pre>
|
||||
<?=$lang['edit']['dkim_record_info'];?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<p>Domain: <strong><?=htmlspecialchars($result['alias_domain']);?></strong> (dkim._domainkey)</p>
|
||||
</div>
|
||||
<div class="col-xs-10">
|
||||
<pre><?=$dkim['dkim_txt'];?></pre>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -395,99 +392,232 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['mailbox']) && filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
||||
$mailbox = $_GET["mailbox"];
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `username`, `domain`, `name`, `quota`, `active` FROM `mailbox` WHERE `username` = :username1");
|
||||
$stmt->execute(array(
|
||||
':username1' => $mailbox,
|
||||
));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if ($result !== false && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $result['domain'])) {
|
||||
$left_m = remaining_specs($result['domain'], $_GET['mailbox'])['left_m'];
|
||||
?>
|
||||
<h4><?=$lang['edit']['mailbox'];?></h4>
|
||||
$mailbox = $_GET["mailbox"];
|
||||
$result = mailbox_get_mailbox_details($mailbox);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['mailbox'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($result['username']);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name"><?=$lang['edit']['full_name'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="name" id="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['quota_mb'];?>:
|
||||
<br /><span id="quotaBadge" class="badge">max. <?=intval($result['max_new_quota'] / 1048576)?> MiB</span>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($result['max_new_quota'] / 1048576);?>" value="<?=intval($result['quota']) / 1048576;?>" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="sender_acl"><?=$lang['edit']['sender_acl'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select data-width="50%" style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
|
||||
<?php
|
||||
$sender_acl_handles = mailbox_get_sender_acl_handles($mailbox);
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_domains']['ro'] as $domain):
|
||||
?>
|
||||
<option data-subtext="Admin" value="<?=htmlspecialchars($domain);?>" disabled selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_addresses']['ro'] as $domain):
|
||||
?>
|
||||
<option data-subtext="Admin" disabled selected><?=htmlspecialchars($alias);?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['fixed_sender_aliases'] as $alias):
|
||||
?>
|
||||
<option data-subtext="Alias" disabled selected><?=htmlspecialchars($alias);?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_domains']['rw'] as $domain):
|
||||
?>
|
||||
<option value="<?=htmlspecialchars($domain);?>" selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_domains']['selectable'] as $domain):
|
||||
?>
|
||||
<option value="<?=htmlspecialchars($domain);?>"><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_addresses']['rw'] as $address):
|
||||
?>
|
||||
<option selected><?=htmlspecialchars($address);?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
foreach ($sender_acl_handles['sender_acl_addresses']['selectable'] as $address):
|
||||
?>
|
||||
<option><?=htmlspecialchars($address);?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password" id="password" placeholder="<?=$lang['edit']['unchanged_if_empty'];?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password2" id="password2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="mailbox_edit_mailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['resource']) && filter_var($_GET["resource"], FILTER_VALIDATE_EMAIL) && !empty($_GET["resource"])) {
|
||||
$resource = $_GET["resource"];
|
||||
$result = mailbox_get_resource_details($resource);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['resource'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<input type="hidden" name="username" value="<?=htmlspecialchars($result['username']);?>">
|
||||
<input type="hidden" name="name" value="<?=htmlspecialchars($result['name']);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name"><?=$lang['edit']['full_name'];?>:</label>
|
||||
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="name" id="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>">
|
||||
<input type="text" class="form-control" name="description" id="description" value="<?=htmlspecialchars($result['description'], ENT_QUOTES, 'UTF-8');?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['quota_mb'];?>:
|
||||
<br /><span id="quotaBadge" class="badge">max. <?=intval($left_m)?> MiB</span>
|
||||
</label>
|
||||
<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['kind'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($left_m);?>" value="<?=intval($result['quota']) / 1048576;?>" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="sender_acl"><?=$lang['edit']['sender_acl'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
|
||||
<?php
|
||||
$rows = get_sender_acl_handles($mailbox, "preselected");
|
||||
while ($row_goto_from_alias = array_shift($rows)):
|
||||
?>
|
||||
<option disabled selected><?=htmlspecialchars($row_goto_from_alias['address']);?></option>
|
||||
<?php
|
||||
endwhile;
|
||||
|
||||
// All manual selected
|
||||
$rows = get_sender_acl_handles($mailbox, "selected");
|
||||
while ($row_selected_sender_acl = array_shift($rows)):
|
||||
if (!filter_var($row_selected_sender_acl['send_as'], FILTER_VALIDATE_EMAIL)):
|
||||
?>
|
||||
<option data-divider="true"></option>
|
||||
<option value="<?=htmlspecialchars($row_selected_sender_acl['send_as']);?>" selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], str_replace('@', '', $row_selected_sender_acl['send_as'])));?></option>
|
||||
<option data-divider="true"></option>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<option selected><?=htmlspecialchars($row_selected_sender_acl['send_as']);?></option>
|
||||
<?php
|
||||
endif;
|
||||
endwhile;
|
||||
|
||||
// Unselected domains
|
||||
$rows = get_sender_acl_handles($mailbox, "unselected-domains");
|
||||
while ($row_unselected_sender_acl = array_shift($rows)):
|
||||
?>
|
||||
<option data-divider="true"></option>
|
||||
<option value="@<?=htmlspecialchars($row_unselected_sender_acl['domain']);?>"><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $row_unselected_sender_acl['domain']));?></option>
|
||||
<option data-divider="true"></option>
|
||||
<?php
|
||||
endwhile;
|
||||
|
||||
// Unselected addresses
|
||||
$rows = get_sender_acl_handles($mailbox, "unselected-addresses");
|
||||
while ($row_unselected_sender_acl = array_shift($rows)):
|
||||
?>
|
||||
<option><?=htmlspecialchars($row_unselected_sender_acl['address']);?></option>
|
||||
<?php
|
||||
endwhile;
|
||||
?>
|
||||
<select name="kind" id="kind" title="<?=$lang['edit']['select'];?>" required>
|
||||
<option value="location" <?=($result['kind'] == "location") ? "selected" : null;?>>Location</option>
|
||||
<option value="group" <?=($result['kind'] == "group") ? "selected" : null;?>>Group</option>
|
||||
<option value="thing" <?=($result['kind'] == "thing") ? "selected" : null;?>>Thing</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password" id="password" placeholder="<?=$lang['edit']['unchanged_if_empty'];?>">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="multiple_bookings" <?=($result['multiple_bookings_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['multiple_bookings'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="mailbox_edit_resource" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user")) {
|
||||
if (isset($_GET['syncjob']) &&
|
||||
is_numeric($_GET['syncjob'])) {
|
||||
$id = $_GET["syncjob"];
|
||||
$result = get_syncjob_details($id);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['syncjob'];?></h4>
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<input type="hidden" name="id" value="<?=htmlspecialchars($result['id']);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="host1"><?=$lang['edit']['hostname'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password2" id="password2">
|
||||
<input type="text" class="form-control" name="host1" id="host1" value="<?=htmlspecialchars($result['host1'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="port1">Port</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="port1" id="port1" min="1" max="65535" value="<?=htmlspecialchars($result['port1'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="user1"><?=$lang['edit']['username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="user1" id="user1" value="<?=htmlspecialchars($result['user1'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password1"><?=$lang['edit']['password'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="password1" id="password1" value="<?=htmlspecialchars($result['password1'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="enc1"><?=$lang['edit']['encryption'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<select id="enc1" name="enc1">
|
||||
<option <?=($result['enc1'] == "TLS") ? "selected" : null;?>>TLS</option>
|
||||
<option <?=($result['enc1'] == "SSL") ? "selected" : null;?>>SSL</option>
|
||||
<option <?=($result['enc1'] == "PLAIN") ? "selected" : null;?>>PLAIN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['edit']['mins_interval'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="mins_interval" min="10" max="3600" value="<?=htmlspecialchars($result['mins_interval'], ENT_QUOTES, 'UTF-8');?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="subfolder2"><?=$lang['edit']['subfolder2'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="subfolder2" id="subfolder2" value="<?=htmlspecialchars($result['subfolder2'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="maxage" id="maxage" value="<?=htmlspecialchars($result['maxage'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="exclude"><?=$lang['edit']['exclude'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="exclude" id="exclude" value="<?=htmlspecialchars($result['exclude'], ENT_QUOTES, 'UTF-8');?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -499,7 +629,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" name="trigger_mailbox_action" value="editmailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
<button type="submit" name="edit_syncjob" value="1" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
BIN
data/web/img/yubi.ico
Normal file
BIN
data/web/img/yubi.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
include("inc/tfa_modals.php");
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<div id="RestartSOGo" class="modal fade" role="dialog">
|
||||
@ -21,10 +22,12 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<div style="margin-bottom:100px"></div>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/7.0.2/bootstrap-slider.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.9.4/js/bootstrap-select.js"></script>
|
||||
<script src="/js/u2f-api.js"></script>
|
||||
<script>
|
||||
// Select language and reopen active URL without POST
|
||||
function setLang(sel) {
|
||||
@ -33,6 +36,93 @@ function setLang(sel) {
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Confirm TFA modal
|
||||
<?php if (isset($_SESSION['pending_tfa_method'])):?>
|
||||
$('#ConfirmTFAModal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: false
|
||||
});
|
||||
$('#ConfirmTFAModal').on('shown.bs.modal', function(){
|
||||
$(this).find('#token').focus();
|
||||
// If U2F
|
||||
if(document.getElementById("u2f_auth_data") !== null) {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
cache: false,
|
||||
dataType: 'script',
|
||||
url: "json_api.php",
|
||||
data: {
|
||||
'action':'get_u2f_auth_challenge',
|
||||
'object':'<?=(isset($_SESSION['pending_mailcow_cc_username'])) ? $_SESSION['pending_mailcow_cc_username'] : null;?>',
|
||||
},
|
||||
success: function(data){
|
||||
data;
|
||||
}
|
||||
});
|
||||
setTimeout(function() {
|
||||
console.log("sign: ", req);
|
||||
u2f.sign(req, function(data) {
|
||||
var form = document.getElementById('u2f_auth_form');
|
||||
var auth = document.getElementById('u2f_auth_data');
|
||||
console.log("Authenticate callback", data);
|
||||
auth.value = JSON.stringify(data);
|
||||
form.submit();
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
<?php endif; ?>
|
||||
|
||||
// Set TFA modals
|
||||
$('#selectTFA').change(function () {
|
||||
if ($(this).val() == "yubi_otp") {
|
||||
$('#YubiOTPModal').modal('show');
|
||||
$("option:selected").prop("selected", false);
|
||||
}
|
||||
if ($(this).val() == "u2f") {
|
||||
$('#U2FModal').modal('show');
|
||||
$("option:selected").prop("selected", false);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
cache: false,
|
||||
dataType: 'script',
|
||||
url: "json_api.php",
|
||||
data: {
|
||||
'action':'get_u2f_reg_challenge',
|
||||
'object':'<?=(isset($_SESSION['mailcow_cc_username'])) ? $_SESSION['mailcow_cc_username'] : null;?>',
|
||||
},
|
||||
success: function(data){
|
||||
data;
|
||||
}
|
||||
});
|
||||
setTimeout(function() {
|
||||
console.log("Register: ", req);
|
||||
u2f.register([req], sigs, function(data) {
|
||||
var form = document.getElementById('u2f_reg_form');
|
||||
var reg = document.getElementById('u2f_register_data');
|
||||
console.log("Register callback", data);
|
||||
if (data.errorCode && data.errorCode != 0) {
|
||||
var u2f_return_code = document.getElementById('u2f_return_code');
|
||||
u2f_return_code.style.display = u2f_return_code.style.display === 'none' ? '' : null;
|
||||
if (data.errorCode == "4") { data.errorCode = "4 - The presented device is not eligible for this request. For a registration request this may mean that the token is already registered, and for a sign request it may mean that the token does not know the presented key handle"; }
|
||||
u2f_return_code.innerHTML = 'Error code: ' + data.errorCode;
|
||||
return;
|
||||
}
|
||||
reg.value = JSON.stringify(data);
|
||||
form.submit();
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
if ($(this).val() == "none") {
|
||||
$('#DisableTFAModal').modal('show');
|
||||
$("option:selected").prop("selected", false);
|
||||
}
|
||||
});
|
||||
|
||||
// Activate tooltips
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
// Hide alerts after n seconds
|
||||
$("#alert-fade").fadeTo(7000, 500).slideUp(500, function(){
|
||||
$("#alert-fade").alert('close');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,157 +17,11 @@
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.min.css">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700&subset=latin,latin-ext">
|
||||
<link rel="stylesheet" href="/inc/languages.min.css">
|
||||
<link rel="stylesheet" href="/css/mailcow.css">
|
||||
<link rel="stylesheet" href="/css/tables.css">
|
||||
<?=(preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null;?>
|
||||
<link rel="shortcut icon" href="/favicon.png" type="image/png">
|
||||
<link rel="icon" href="/favicon.png" type="image/png">
|
||||
<style>
|
||||
#maxmsgsize { min-width: 80px; }
|
||||
ul[id*="sortable"] { word-wrap: break-word; list-style-type: none; float: left; padding: 0 15px 0 0; width: 48%; cursor:move}
|
||||
ul[id$="sortable-active"] li {cursor:move; }
|
||||
ul[id$="sortable-inactive"] li {cursor:move }
|
||||
.list-heading { cursor:default !important}
|
||||
.ui-state-disabled { cursor:no-drop; color:#ccc; }
|
||||
.ui-state-highlight {background: #F5F5F5 !important; height: 41px !important; cursor:move }
|
||||
#slider1 .slider-selection {
|
||||
background: #FFD700;
|
||||
}
|
||||
#slider1 .slider-track-high {
|
||||
background: #FF4500;
|
||||
}
|
||||
#slider1 .slider-track-low {
|
||||
background: #66CD00;
|
||||
}
|
||||
table[data-sortable] {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
table[data-sortable] th {
|
||||
vertical-align: bottom;
|
||||
font-weight: bold;
|
||||
}
|
||||
table[data-sortable] th, table[data-sortable] td {
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
}
|
||||
table[data-sortable] th:not([data-sortable="false"]) {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-touch-callout: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
table[data-sortable] th:after {
|
||||
content: "";
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
vertical-align: inherit;
|
||||
height: 0;
|
||||
width: 0;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
margin-right: 1px;
|
||||
margin-left: 10px;
|
||||
float: right;
|
||||
}
|
||||
table[data-sortable] th[data-sortable="false"]:after {
|
||||
display: none;
|
||||
}
|
||||
table[data-sortable] th[data-sorted="true"]:after {
|
||||
visibility: visible;
|
||||
}
|
||||
table[data-sortable] th[data-sorted-direction="descending"]:after {
|
||||
border-top-color: inherit;
|
||||
margin-top: 8px;
|
||||
}
|
||||
table[data-sortable] th[data-sorted-direction="ascending"]:after {
|
||||
border-bottom-color: inherit;
|
||||
margin-top: 3px;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap thead th {
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"] {
|
||||
color: #3a87ad;
|
||||
background: #d9edf7;
|
||||
border-bottom-color: #bce8f1;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="descending"]:after {
|
||||
border-top-color: #3a87ad;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="ascending"]:after {
|
||||
border-bottom-color: #3a87ad;
|
||||
}
|
||||
table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped tbody > tr:nth-child(odd) > td {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.btn {
|
||||
text-transform: none;
|
||||
}
|
||||
#data td, #no-data td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.sort-table:hover {
|
||||
border-bottom-color: #00B7DC !important;
|
||||
}
|
||||
.striped:nth-child(odd) {
|
||||
background-color: #fff;
|
||||
}
|
||||
.striped:nth-child(even) {
|
||||
background-color: #fafafa;
|
||||
border:1px solid white;
|
||||
}
|
||||
.glyphicon-spin {
|
||||
-webkit-animation: spin 1000ms infinite linear;
|
||||
animation: spin 1000ms infinite linear;
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
if (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])):
|
||||
?>
|
||||
<style>
|
||||
.panel-heading div {
|
||||
margin-top: -18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.panel-heading div span {
|
||||
margin-left:5px;
|
||||
}
|
||||
.panel-body {
|
||||
display: none;
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.progress {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</head>
|
||||
<body style="padding-top:70px">
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
@ -214,11 +68,11 @@ endif;
|
||||
<li <?=(preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? 'class="active"' : ''?>><a href="/mailbox.php"><?=$lang['header']['mailboxes'];?></a></li>
|
||||
<?php
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "user") {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
?>
|
||||
<li <?=(preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? 'class="active"' : ''?>><a href="/user.php"><?=$lang['header']['user_settings'];?></a></li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
@ -232,10 +86,14 @@ endif;
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
if (isset($_SESSION['mailcow_cc_username'])):
|
||||
if (!isset($_SESSION["dual-login"]) && isset($_SESSION['mailcow_cc_username'])):
|
||||
?>
|
||||
<li><a style="border-left:1px solid #E7E7E7" href="#" onclick="logout.submit()"><?=sprintf($lang['header']['logged_in_as_logout'], $_SESSION['mailcow_cc_username']);?></a></li>
|
||||
<?php
|
||||
elseif (isset($_SESSION["dual-login"])):
|
||||
?>
|
||||
<li><a style="border-left:1px solid #E7E7E7" href="#" onclick="logout.submit()"><?=sprintf($lang['header']['logged_in_as_logout_dual'], $_SESSION['mailcow_cc_username'], $_SESSION["dual-login"]["username"]);?></a></li>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</ul>
|
||||
|
@ -1,107 +1,145 @@
|
||||
CREATE TABLE IF NOT EXISTS `admin` (
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`superadmin` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`username` VARCHAR(255) NOT NULL,
|
||||
`password` VARCHAR(255) NOT NULL,
|
||||
`superadmin` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `alias` (
|
||||
`address` varchar(255) NOT NULL,
|
||||
`goto` text NOT NULL,
|
||||
`domain` varchar(255) NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`address` VARCHAR(255) NOT NULL,
|
||||
`goto` TEXT NOT NULL,
|
||||
`domain` VARCHAR(255) NOT NULL,
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`address`),
|
||||
KEY `domain` (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sender_acl` (
|
||||
`logged_in_as` varchar(255) NOT NULL,
|
||||
`send_as` varchar(255) NOT NULL
|
||||
`logged_in_as` VARCHAR(255) NOT NULL,
|
||||
`send_as` VARCHAR(255) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `spamalias` (
|
||||
`address` varchar(255) NOT NULL,
|
||||
`goto` text NOT NULL,
|
||||
`validity` int(11) NOT NULL,
|
||||
`address` VARCHAR(255) NOT NULL,
|
||||
`goto` TEXT NOT NULL,
|
||||
`validity` INT(11) NOT NULL,
|
||||
PRIMARY KEY (`address`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `alias_domain` (
|
||||
`alias_domain` varchar(255) NOT NULL,
|
||||
`target_domain` varchar(255) NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`alias_domain` VARCHAR(255) NOT NULL,
|
||||
`target_domain` VARCHAR(255) NOT NULL,
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`alias_domain`),
|
||||
KEY `active` (`active`),
|
||||
KEY `target_domain` (`target_domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `domain` (
|
||||
`domain` varchar(255) NOT NULL,
|
||||
`description` varchar(255),
|
||||
`aliases` int(10) NOT NULL DEFAULT '0',
|
||||
`mailboxes` int(10) NOT NULL DEFAULT '0',
|
||||
`maxquota` bigint(20) NOT NULL DEFAULT '0',
|
||||
`quota` bigint(20) NOT NULL DEFAULT '0',
|
||||
`transport` varchar(255) NOT NULL,
|
||||
`backupmx` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`relay_all_recipients` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`domain` VARCHAR(255) NOT NULL,
|
||||
`description` VARCHAR(255),
|
||||
`aliases` INT(10) NOT NULL DEFAULT '0',
|
||||
`mailboxes` INT(10) NOT NULL DEFAULT '0',
|
||||
`maxquota` BIGINT(20) NOT NULL DEFAULT '0',
|
||||
`quota` BIGINT(20) NOT NULL DEFAULT '0',
|
||||
`transport` VARCHAR(255) NOT NULL,
|
||||
`backupmx` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`relay_all_recipients` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `domain_admins` (
|
||||
`username` varchar(255) NOT NULL,
|
||||
`domain` varchar(255) NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`username` VARCHAR(255) NOT NULL,
|
||||
`domain` VARCHAR(255) NOT NULL,
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
KEY `username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `mailbox` (
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`name` varchar(255),
|
||||
`maildir` varchar(255) NOT NULL,
|
||||
`quota` bigint(20) NOT NULL DEFAULT '0',
|
||||
`local_part` varchar(255) NOT NULL,
|
||||
`domain` varchar(255) NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`tls_enforce_in` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`tls_enforce_out` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`kind` varchar(100) NOT NULL DEFAULT '',
|
||||
`multiple_bookings` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`username` VARCHAR(255) NOT NULL,
|
||||
`password` VARCHAR(255) NOT NULL,
|
||||
`name` VARCHAR(255),
|
||||
`maildir` VARCHAR(255) NOT NULL,
|
||||
`quota` BIGINT(20) NOT NULL DEFAULT '0',
|
||||
`local_part` VARCHAR(255) NOT NULL,
|
||||
`domain` VARCHAR(255) NOT NULL,
|
||||
`created` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`modified` DATETIME NOT NULL DEFAULT '2016-01-01 00:00:00',
|
||||
`tls_enforce_in` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`tls_enforce_out` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`kind` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`multiple_bookings` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`wants_tagged_subject` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`username`),
|
||||
KEY `domain` (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `quota2` (
|
||||
`username` varchar(100) NOT NULL,
|
||||
`bytes` bigint(20) NOT NULL DEFAULT '0',
|
||||
`messages` int(11) NOT NULL DEFAULT '0',
|
||||
`username` VARCHAR(100) NOT NULL,
|
||||
`bytes` BIGINT(20) NOT NULL DEFAULT '0',
|
||||
`messages` INT(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `filterconf` (
|
||||
`object` varchar(100) NOT NULL DEFAULT '',
|
||||
`option` varchar(50) NOT NULL DEFAULT '',
|
||||
`value` varchar(100) NOT NULL DEFAULT '',
|
||||
`prefid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`object` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`option` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`value` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`prefid` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`prefid`),
|
||||
KEY `object` (`object`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `imapsync` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`user2` VARCHAR(255) NOT NULL,
|
||||
`host1` VARCHAR(255) NOT NULL,
|
||||
`authmech1` ENUM('PLAIN','LOGIN','CRAM-MD5') DEFAULT 'PLAIN',
|
||||
`regextrans2` VARCHAR(255) DEFAULT '',
|
||||
`authmd51` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`domain2` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`subfolder2` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`user1` VARCHAR(255) NOT NULL,
|
||||
`password1` VARCHAR(255) NOT NULL,
|
||||
`exclude` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`maxage` SMALLINT NOT NULL DEFAULT '0',
|
||||
`mins_interval` VARCHAR(50) NOT NULL,
|
||||
`port1` SMALLINT NOT NULL,
|
||||
`enc1` ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS',
|
||||
`delete2duplicates` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
`returned_text` TEXT,
|
||||
`last_run` TIMESTAMP NULL DEFAULT NULL,
|
||||
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tfa` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`username` VARCHAR(255) NOT NULL,
|
||||
`authmech` ENUM('yubi_otp', 'u2f', 'hotp', 'totp'),
|
||||
`secret` VARCHAR(255) DEFAULT NULL,
|
||||
`keyHandle` VARCHAR(255) DEFAULT NULL,
|
||||
`publicKey` VARCHAR(255) DEFAULT NULL,
|
||||
`counter` INT NOT NULL DEFAULT '0',
|
||||
`certificate` TEXT,
|
||||
`active` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
DROP VIEW IF EXISTS grouped_mail_aliases;
|
||||
DROP VIEW IF EXISTS grouped_sender_acl;
|
||||
DROP VIEW IF EXISTS grouped_domain_alias_address;
|
||||
@ -123,80 +161,80 @@ SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '
|
||||
LEFT OUTER JOIN alias_domain on target_domain=domain GROUP BY username;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_acl (
|
||||
c_folder_id integer NOT NULL,
|
||||
c_folder_id INTEGER NOT NULL,
|
||||
c_object character varying(255) NOT NULL,
|
||||
c_uid character varying(255) NOT NULL,
|
||||
c_role character varying(80) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_alarms_folder (
|
||||
c_path varchar(255) NOT NULL,
|
||||
c_name varchar(255) NOT NULL,
|
||||
c_uid varchar(255) NOT NULL,
|
||||
c_recurrence_id int(11) DEFAULT NULL,
|
||||
c_alarm_number int(11) NOT NULL,
|
||||
c_alarm_date int(11) NOT NULL
|
||||
c_path VARCHAR(255) NOT NULL,
|
||||
c_name VARCHAR(255) NOT NULL,
|
||||
c_uid VARCHAR(255) NOT NULL,
|
||||
c_recurrence_id INT(11) DEFAULT NULL,
|
||||
c_alarm_number INT(11) NOT NULL,
|
||||
c_alarm_date INT(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_cache_folder (
|
||||
c_uid varchar(255) NOT NULL,
|
||||
c_path varchar(255) NOT NULL,
|
||||
c_parent_path varchar(255) DEFAULT NULL,
|
||||
c_type tinyint(3) unsigned NOT NULL,
|
||||
c_creationdate int(11) NOT NULL,
|
||||
c_lastmodified int(11) NOT NULL,
|
||||
c_version int(11) NOT NULL DEFAULT '0',
|
||||
c_deleted tinyint(4) NOT NULL DEFAULT '0',
|
||||
c_content longtext,
|
||||
c_uid VARCHAR(255) NOT NULL,
|
||||
c_path VARCHAR(255) NOT NULL,
|
||||
c_parent_path VARCHAR(255) DEFAULT NULL,
|
||||
c_type TINYINT(3) unsigned NOT NULL,
|
||||
c_creationdate INT(11) NOT NULL,
|
||||
c_lastmodified INT(11) NOT NULL,
|
||||
c_version INT(11) NOT NULL DEFAULT '0',
|
||||
c_deleted TINYINT(4) NOT NULL DEFAULT '0',
|
||||
c_content longTEXT,
|
||||
PRIMARY KEY (c_uid,c_path)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_folder_info (
|
||||
c_folder_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
c_path varchar(255) NOT NULL,
|
||||
c_path1 varchar(255) NOT NULL,
|
||||
c_path2 varchar(255) DEFAULT NULL,
|
||||
c_path3 varchar(255) DEFAULT NULL,
|
||||
c_path4 varchar(255) DEFAULT NULL,
|
||||
c_foldername varchar(255) NOT NULL,
|
||||
c_location integer NULL,
|
||||
c_quick_location varchar(2048) DEFAULT NULL,
|
||||
c_acl_location varchar(2048) DEFAULT NULL,
|
||||
c_folder_type varchar(255) NOT NULL,
|
||||
c_folder_id BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
c_path VARCHAR(255) NOT NULL,
|
||||
c_path1 VARCHAR(255) NOT NULL,
|
||||
c_path2 VARCHAR(255) DEFAULT NULL,
|
||||
c_path3 VARCHAR(255) DEFAULT NULL,
|
||||
c_path4 VARCHAR(255) DEFAULT NULL,
|
||||
c_foldername VARCHAR(255) NOT NULL,
|
||||
c_location INTeger NULL,
|
||||
c_quick_location VARCHAR(2048) DEFAULT NULL,
|
||||
c_acl_location VARCHAR(2048) DEFAULT NULL,
|
||||
c_folder_type VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (c_path),
|
||||
UNIQUE KEY c_folder_id (c_folder_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_quick_appointment (
|
||||
c_folder_id integer NOT NULL,
|
||||
c_folder_id INTeger NOT NULL,
|
||||
c_name character varying(255) NOT NULL,
|
||||
c_uid character varying(255) NOT NULL,
|
||||
c_startdate integer,
|
||||
c_enddate integer,
|
||||
c_cycleenddate integer,
|
||||
c_startdate INTeger,
|
||||
c_enddate INTeger,
|
||||
c_cycleenddate INTeger,
|
||||
c_title character varying(1000) NOT NULL,
|
||||
c_participants text,
|
||||
c_isallday integer,
|
||||
c_iscycle integer,
|
||||
c_cycleinfo text,
|
||||
c_classification integer NOT NULL,
|
||||
c_isopaque integer NOT NULL,
|
||||
c_status integer NOT NULL,
|
||||
c_priority integer,
|
||||
c_participants TEXT,
|
||||
c_isallday INTeger,
|
||||
c_iscycle INTeger,
|
||||
c_cycleinfo TEXT,
|
||||
c_classification INTeger NOT NULL,
|
||||
c_isopaque INTeger NOT NULL,
|
||||
c_status INTeger NOT NULL,
|
||||
c_priority INTeger,
|
||||
c_location character varying(255),
|
||||
c_orgmail character varying(255),
|
||||
c_partmails text,
|
||||
c_partstates text,
|
||||
c_partmails TEXT,
|
||||
c_partstates TEXT,
|
||||
c_category character varying(255),
|
||||
c_sequence integer,
|
||||
c_sequence INTeger,
|
||||
c_component character varying(10) NOT NULL,
|
||||
c_nextalarm integer,
|
||||
c_description text,
|
||||
c_nextalarm INTeger,
|
||||
c_description TEXT,
|
||||
CONSTRAINT sogo_quick_appointment_pkey PRIMARY KEY (c_folder_id, c_name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_quick_contact (
|
||||
c_folder_id integer NOT NULL,
|
||||
c_folder_id INTeger NOT NULL,
|
||||
c_name character varying(255) NOT NULL,
|
||||
c_givenname character varying(255),
|
||||
c_cn character varying(255),
|
||||
@ -213,28 +251,28 @@ CREATE TABLE IF NOT EXISTS sogo_quick_contact (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_sessions_folder (
|
||||
c_id varchar(255) NOT NULL,
|
||||
c_value varchar(255) NOT NULL,
|
||||
c_creationdate int(11) NOT NULL,
|
||||
c_lastseen int(11) NOT NULL,
|
||||
c_id VARCHAR(255) NOT NULL,
|
||||
c_value VARCHAR(255) NOT NULL,
|
||||
c_creationdate INT(11) NOT NULL,
|
||||
c_lastseen INT(11) NOT NULL,
|
||||
PRIMARY KEY (c_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_store (
|
||||
c_folder_id integer NOT NULL,
|
||||
c_folder_id INTeger NOT NULL,
|
||||
c_name character varying(255) NOT NULL,
|
||||
c_content mediumtext NOT NULL,
|
||||
c_creationdate integer NOT NULL,
|
||||
c_lastmodified integer NOT NULL,
|
||||
c_version integer NOT NULL,
|
||||
c_deleted integer,
|
||||
c_content mediumTEXT NOT NULL,
|
||||
c_creationdate INTeger NOT NULL,
|
||||
c_lastmodified INTeger NOT NULL,
|
||||
c_version INTeger NOT NULL,
|
||||
c_deleted INTeger,
|
||||
CONSTRAINT sogo_store_pkey PRIMARY KEY (c_folder_id, c_name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sogo_user_profile (
|
||||
c_uid varchar(255) NOT NULL,
|
||||
c_defaults text,
|
||||
c_settings text,
|
||||
c_uid VARCHAR(255) NOT NULL,
|
||||
c_defaults TEXT,
|
||||
c_settings TEXT,
|
||||
PRIMARY KEY (c_uid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
|
506
data/web/inc/lib/U2F.php
Normal file
506
data/web/inc/lib/U2F.php
Normal file
@ -0,0 +1,506 @@
|
||||
<?php
|
||||
/* Copyright (c) 2014 Yubico AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace u2flib_server;
|
||||
|
||||
/** Constant for the version of the u2f protocol */
|
||||
const U2F_VERSION = "U2F_V2";
|
||||
|
||||
/** Error for the authentication message not matching any outstanding
|
||||
* authentication request */
|
||||
const ERR_NO_MATCHING_REQUEST = 1;
|
||||
|
||||
/** Error for the authentication message not matching any registration */
|
||||
const ERR_NO_MATCHING_REGISTRATION = 2;
|
||||
|
||||
/** Error for the signature on the authentication message not verifying with
|
||||
* the correct key */
|
||||
const ERR_AUTHENTICATION_FAILURE = 3;
|
||||
|
||||
/** Error for the challenge in the registration message not matching the
|
||||
* registration challenge */
|
||||
const ERR_UNMATCHED_CHALLENGE = 4;
|
||||
|
||||
/** Error for the attestation signature on the registration message not
|
||||
* verifying */
|
||||
const ERR_ATTESTATION_SIGNATURE = 5;
|
||||
|
||||
/** Error for the attestation verification not verifying */
|
||||
const ERR_ATTESTATION_VERIFICATION = 6;
|
||||
|
||||
/** Error for not getting good random from the system */
|
||||
const ERR_BAD_RANDOM = 7;
|
||||
|
||||
/** Error when the counter is lower than expected */
|
||||
const ERR_COUNTER_TOO_LOW = 8;
|
||||
|
||||
/** Error decoding public key */
|
||||
const ERR_PUBKEY_DECODE = 9;
|
||||
|
||||
/** Error user-agent returned error */
|
||||
const ERR_BAD_UA_RETURNING = 10;
|
||||
|
||||
/** Error old OpenSSL version */
|
||||
const ERR_OLD_OPENSSL = 11;
|
||||
|
||||
/** @internal */
|
||||
const PUBKEY_LEN = 65;
|
||||
|
||||
class U2F
|
||||
{
|
||||
/** @var string */
|
||||
private $appId;
|
||||
|
||||
/** @var null|string */
|
||||
private $attestDir;
|
||||
|
||||
/** @internal */
|
||||
private $FIXCERTS = array(
|
||||
'349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
|
||||
'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
|
||||
'1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
|
||||
'd0edc9a91a1677435a953390865d208c55b3183c6759c9b5a7ff494c322558eb',
|
||||
'6073c436dcd064a48127ddbf6032ac1a66fd59a0c24434f070d4e564c124c897',
|
||||
'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
|
||||
);
|
||||
|
||||
/**
|
||||
* @param string $appId Application id for the running application
|
||||
* @param string|null $attestDir Directory where trusted attestation roots may be found
|
||||
* @throws Error If OpenSSL older than 1.0.0 is used
|
||||
*/
|
||||
public function __construct($appId, $attestDir = null)
|
||||
{
|
||||
if(OPENSSL_VERSION_NUMBER < 0x10000000) {
|
||||
throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
|
||||
}
|
||||
$this->appId = $appId;
|
||||
$this->attestDir = $attestDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to get a registration request to send to a user.
|
||||
* Returns an array of one registration request and a array of sign requests.
|
||||
*
|
||||
* @param array $registrations List of current registrations for this
|
||||
* user, to prevent the user from registering the same authenticator several
|
||||
* times.
|
||||
* @return array An array of two elements, the first containing a
|
||||
* RegisterRequest the second being an array of SignRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function getRegisterData(array $registrations = array())
|
||||
{
|
||||
$challenge = $this->createChallenge();
|
||||
$request = new RegisterRequest($challenge, $this->appId);
|
||||
$signs = $this->getAuthenticateData($registrations);
|
||||
return array($request, $signs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to verify and unpack a registration message.
|
||||
*
|
||||
* @param RegisterRequest $request this is a reply to
|
||||
* @param object $response response from a user
|
||||
* @param bool $includeCert set to true if the attestation certificate should be
|
||||
* included in the returned Registration object
|
||||
* @return Registration
|
||||
* @throws Error
|
||||
*/
|
||||
public function doRegister($request, $response, $includeCert = true)
|
||||
{
|
||||
if( !is_object( $request ) ) {
|
||||
throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
|
||||
}
|
||||
|
||||
if( !is_object( $response ) ) {
|
||||
throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
|
||||
}
|
||||
|
||||
if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
|
||||
throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
|
||||
}
|
||||
|
||||
if( !is_bool( $includeCert ) ) {
|
||||
throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
|
||||
}
|
||||
|
||||
$rawReg = $this->base64u_decode($response->registrationData);
|
||||
$regData = array_values(unpack('C*', $rawReg));
|
||||
$clientData = $this->base64u_decode($response->clientData);
|
||||
$cli = json_decode($clientData);
|
||||
|
||||
if($cli->challenge !== $request->challenge) {
|
||||
throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE );
|
||||
}
|
||||
|
||||
$registration = new Registration();
|
||||
$offs = 1;
|
||||
$pubKey = substr($rawReg, $offs, PUBKEY_LEN);
|
||||
$offs += PUBKEY_LEN;
|
||||
// decode the pubKey to make sure it's good
|
||||
$tmpKey = $this->pubkey_to_pem($pubKey);
|
||||
if($tmpKey === null) {
|
||||
throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
|
||||
}
|
||||
$registration->publicKey = base64_encode($pubKey);
|
||||
$khLen = $regData[$offs++];
|
||||
$kh = substr($rawReg, $offs, $khLen);
|
||||
$offs += $khLen;
|
||||
$registration->keyHandle = $this->base64u_encode($kh);
|
||||
|
||||
// length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
|
||||
$certLen = 4;
|
||||
$certLen += ($regData[$offs + 2] << 8);
|
||||
$certLen += $regData[$offs + 3];
|
||||
|
||||
$rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
|
||||
$offs += $certLen;
|
||||
$pemCert = "-----BEGIN CERTIFICATE-----\r\n";
|
||||
$pemCert .= chunk_split(base64_encode($rawCert), 64);
|
||||
$pemCert .= "-----END CERTIFICATE-----";
|
||||
if($includeCert) {
|
||||
$registration->certificate = base64_encode($rawCert);
|
||||
}
|
||||
if($this->attestDir) {
|
||||
if(openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
|
||||
throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION );
|
||||
}
|
||||
}
|
||||
|
||||
if(!openssl_pkey_get_public($pemCert)) {
|
||||
throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
|
||||
}
|
||||
$signature = substr($rawReg, $offs);
|
||||
|
||||
$dataToVerify = chr(0);
|
||||
$dataToVerify .= hash('sha256', $request->appId, true);
|
||||
$dataToVerify .= hash('sha256', $clientData, true);
|
||||
$dataToVerify .= $kh;
|
||||
$dataToVerify .= $pubKey;
|
||||
|
||||
if(openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
|
||||
return $registration;
|
||||
} else {
|
||||
throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to get an authentication request.
|
||||
*
|
||||
* @param array $registrations An array of the registrations to create authentication requests for.
|
||||
* @return array An array of SignRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function getAuthenticateData(array $registrations)
|
||||
{
|
||||
$sigs = array();
|
||||
foreach ($registrations as $reg) {
|
||||
if( !is_object( $reg ) ) {
|
||||
throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
|
||||
}
|
||||
|
||||
$sig = new SignRequest();
|
||||
$sig->appId = $this->appId;
|
||||
$sig->keyHandle = $reg->keyHandle;
|
||||
$sig->challenge = $this->createChallenge();
|
||||
$sigs[] = $sig;
|
||||
}
|
||||
return $sigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to verify an authentication response
|
||||
*
|
||||
* @param array $requests An array of outstanding authentication requests
|
||||
* @param array $registrations An array of current registrations
|
||||
* @param object $response A response from the authenticator
|
||||
* @return Registration
|
||||
* @throws Error
|
||||
*
|
||||
* The Registration object returned on success contains an updated counter
|
||||
* that should be saved for future authentications.
|
||||
* If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
|
||||
* token cloning or similar and appropriate action should be taken.
|
||||
*/
|
||||
public function doAuthenticate(array $requests, array $registrations, $response)
|
||||
{
|
||||
if( !is_object( $response ) ) {
|
||||
throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
|
||||
}
|
||||
|
||||
if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
|
||||
throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
|
||||
}
|
||||
|
||||
/** @var object|null $req */
|
||||
$req = null;
|
||||
|
||||
/** @var object|null $reg */
|
||||
$reg = null;
|
||||
|
||||
$clientData = $this->base64u_decode($response->clientData);
|
||||
$decodedClient = json_decode($clientData);
|
||||
foreach ($requests as $req) {
|
||||
if( !is_object( $req ) ) {
|
||||
throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
|
||||
}
|
||||
|
||||
if($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
|
||||
break;
|
||||
}
|
||||
|
||||
$req = null;
|
||||
}
|
||||
if($req === null) {
|
||||
throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST );
|
||||
}
|
||||
foreach ($registrations as $reg) {
|
||||
if( !is_object( $reg ) ) {
|
||||
throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
|
||||
}
|
||||
|
||||
if($reg->keyHandle === $response->keyHandle) {
|
||||
break;
|
||||
}
|
||||
$reg = null;
|
||||
}
|
||||
if($reg === null) {
|
||||
throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION );
|
||||
}
|
||||
$pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
|
||||
if($pemKey === null) {
|
||||
throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
|
||||
}
|
||||
|
||||
$signData = $this->base64u_decode($response->signatureData);
|
||||
$dataToVerify = hash('sha256', $req->appId, true);
|
||||
$dataToVerify .= substr($signData, 0, 5);
|
||||
$dataToVerify .= hash('sha256', $clientData, true);
|
||||
$signature = substr($signData, 5);
|
||||
|
||||
if(openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
|
||||
$ctr = unpack("Nctr", substr($signData, 1, 4));
|
||||
$counter = $ctr['ctr'];
|
||||
/* TODO: wrap-around should be handled somehow.. */
|
||||
if($counter > $reg->counter) {
|
||||
$reg->counter = $counter;
|
||||
return $reg;
|
||||
} else {
|
||||
throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW );
|
||||
}
|
||||
} else {
|
||||
throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_certs()
|
||||
{
|
||||
$files = array();
|
||||
$dir = $this->attestDir;
|
||||
if($dir && $handle = opendir($dir)) {
|
||||
while(false !== ($entry = readdir($handle))) {
|
||||
if(is_file("$dir/$entry")) {
|
||||
$files[] = "$dir/$entry";
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
private function base64u_encode($data)
|
||||
{
|
||||
return trim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
private function base64u_decode($data)
|
||||
{
|
||||
return base64_decode(strtr($data, '-_', '+/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return null|string
|
||||
*/
|
||||
private function pubkey_to_pem($key)
|
||||
{
|
||||
if(strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the public key to binary DER format first
|
||||
* Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
|
||||
*
|
||||
* SEQUENCE(2 elem) 30 59
|
||||
* SEQUENCE(2 elem) 30 13
|
||||
* OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
|
||||
* OID1.2.840.10045.3.1.7 (secp256r1) 06 08 2a 86 48 ce 3d 03 01 07
|
||||
* BIT STRING(520 bit) 03 42 ..key..
|
||||
*/
|
||||
$der = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
|
||||
$der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
|
||||
$der .= "\0".$key;
|
||||
|
||||
$pem = "-----BEGIN PUBLIC KEY-----\r\n";
|
||||
$pem .= chunk_split(base64_encode($der), 64);
|
||||
$pem .= "-----END PUBLIC KEY-----";
|
||||
|
||||
return $pem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Error
|
||||
*/
|
||||
private function createChallenge()
|
||||
{
|
||||
$challenge = openssl_random_pseudo_bytes(32, $crypto_strong );
|
||||
if( $crypto_strong !== true ) {
|
||||
throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
|
||||
}
|
||||
|
||||
$challenge = $this->base64u_encode( $challenge );
|
||||
|
||||
return $challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes a certificate where the signature contains unused bits.
|
||||
*
|
||||
* @param string $cert
|
||||
* @return mixed
|
||||
*/
|
||||
private function fixSignatureUnusedBits($cert)
|
||||
{
|
||||
if(in_array(hash('sha256', $cert), $this->FIXCERTS)) {
|
||||
$cert[strlen($cert) - 257] = "\0";
|
||||
}
|
||||
return $cert;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for building a registration request
|
||||
*
|
||||
* @package u2flib_server
|
||||
*/
|
||||
class RegisterRequest
|
||||
{
|
||||
/** Protocol version */
|
||||
public $version = U2F_VERSION;
|
||||
|
||||
/** Registration challenge */
|
||||
public $challenge;
|
||||
|
||||
/** Application id */
|
||||
public $appId;
|
||||
|
||||
/**
|
||||
* @param string $challenge
|
||||
* @param string $appId
|
||||
* @internal
|
||||
*/
|
||||
public function __construct($challenge, $appId)
|
||||
{
|
||||
$this->challenge = $challenge;
|
||||
$this->appId = $appId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for building up an authentication request
|
||||
*
|
||||
* @package u2flib_server
|
||||
*/
|
||||
class SignRequest
|
||||
{
|
||||
/** Protocol version */
|
||||
public $version = U2F_VERSION;
|
||||
|
||||
/** Authentication challenge */
|
||||
public $challenge;
|
||||
|
||||
/** Key handle of a registered authenticator */
|
||||
public $keyHandle;
|
||||
|
||||
/** Application id */
|
||||
public $appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class returned for successful registrations
|
||||
*
|
||||
* @package u2flib_server
|
||||
*/
|
||||
class Registration
|
||||
{
|
||||
/** The key handle of the registered authenticator */
|
||||
public $keyHandle;
|
||||
|
||||
/** The public key of the registered authenticator */
|
||||
public $publicKey;
|
||||
|
||||
/** The attestation certificate of the registered authenticator */
|
||||
public $certificate;
|
||||
|
||||
/** The counter associated with this registration */
|
||||
public $counter = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class, returned on errors
|
||||
*
|
||||
* @package u2flib_server
|
||||
*/
|
||||
class Error extends \Exception
|
||||
{
|
||||
/**
|
||||
* Override constructor and make message and code mandatory
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param \Exception|null $previous
|
||||
*/
|
||||
public function __construct($message, $code, \Exception $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
475
data/web/inc/lib/Yubico.php
Normal file
475
data/web/inc/lib/Yubico.php
Normal file
@ -0,0 +1,475 @@
|
||||
<?php
|
||||
/**
|
||||
* Class for verifying Yubico One-Time-Passcodes
|
||||
*
|
||||
* @category Auth
|
||||
* @package Auth_Yubico
|
||||
* @author Simon Josefsson <simon@yubico.com>, Olov Danielson <olov@yubico.com>
|
||||
* @copyright 2007-2015 Yubico AB
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version 2.0
|
||||
* @link http://www.yubico.com/
|
||||
*/
|
||||
|
||||
require_once 'PEAR.php';
|
||||
|
||||
/**
|
||||
* Class for verifying Yubico One-Time-Passcodes
|
||||
*
|
||||
* Simple example:
|
||||
* <code>
|
||||
* require_once 'Auth/Yubico.php';
|
||||
* $otp = "ccbbddeertkrctjkkcglfndnlihhnvekchkcctif";
|
||||
*
|
||||
* # Generate a new id+key from https://api.yubico.com/get-api-key/
|
||||
* $yubi = new Auth_Yubico('42', 'FOOBAR=');
|
||||
* $auth = $yubi->verify($otp);
|
||||
* if (PEAR::isError($auth)) {
|
||||
* print "<p>Authentication failed: " . $auth->getMessage();
|
||||
* print "<p>Debug output from server: " . $yubi->getLastResponse();
|
||||
* } else {
|
||||
* print "<p>You are authenticated!";
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
class Auth_Yubico
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Yubico client ID
|
||||
* @var string
|
||||
*/
|
||||
var $_id;
|
||||
|
||||
/**
|
||||
* Yubico client key
|
||||
* @var string
|
||||
*/
|
||||
var $_key;
|
||||
|
||||
/**
|
||||
* URL part of validation server
|
||||
* @var string
|
||||
*/
|
||||
var $_url;
|
||||
|
||||
/**
|
||||
* List with URL part of validation servers
|
||||
* @var array
|
||||
*/
|
||||
var $_url_list;
|
||||
|
||||
/**
|
||||
* index to _url_list
|
||||
* @var int
|
||||
*/
|
||||
var $_url_index;
|
||||
|
||||
/**
|
||||
* Last query to server
|
||||
* @var string
|
||||
*/
|
||||
var $_lastquery;
|
||||
|
||||
/**
|
||||
* Response from server
|
||||
* @var string
|
||||
*/
|
||||
var $_response;
|
||||
|
||||
/**
|
||||
* Flag whether to use https or not.
|
||||
* @var boolean
|
||||
*/
|
||||
var $_https;
|
||||
|
||||
/**
|
||||
* Flag whether to verify HTTPS server certificates or not.
|
||||
* @var boolean
|
||||
*/
|
||||
var $_httpsverify;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Sets up the object
|
||||
* @param string $id The client identity
|
||||
* @param string $key The client MAC key (optional)
|
||||
* @param boolean $https Flag whether to use https (optional)
|
||||
* @param boolean $httpsverify Flag whether to use verify HTTPS
|
||||
* server certificates (optional,
|
||||
* default true)
|
||||
* @access public
|
||||
*/
|
||||
function __construct($id, $key = '', $https = 0, $httpsverify = 1)
|
||||
{
|
||||
$this->_id = $id;
|
||||
$this->_key = base64_decode($key);
|
||||
$this->_https = $https;
|
||||
$this->_httpsverify = $httpsverify;
|
||||
}
|
||||
|
||||
function Auth_Yubico($id, $key = '', $https = 0, $httpsverify = 1)
|
||||
{
|
||||
self::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify to use a different URL part for verification.
|
||||
* The default is "api.yubico.com/wsapi/verify".
|
||||
*
|
||||
* @param string $url New server URL part to use
|
||||
* @access public
|
||||
*/
|
||||
function setURLpart($url)
|
||||
{
|
||||
$this->_url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL part to use for validation.
|
||||
*
|
||||
* @return string Server URL part
|
||||
* @access public
|
||||
*/
|
||||
function getURLpart()
|
||||
{
|
||||
if ($this->_url) {
|
||||
return $this->_url;
|
||||
} else {
|
||||
return "api.yubico.com/wsapi/verify";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get next URL part from list to use for validation.
|
||||
*
|
||||
* @return mixed string with URL part of false if no more URLs in list
|
||||
* @access public
|
||||
*/
|
||||
function getNextURLpart()
|
||||
{
|
||||
if ($this->_url_list) $url_list=$this->_url_list;
|
||||
else $url_list=array('api.yubico.com/wsapi/2.0/verify',
|
||||
'api2.yubico.com/wsapi/2.0/verify',
|
||||
'api3.yubico.com/wsapi/2.0/verify',
|
||||
'api4.yubico.com/wsapi/2.0/verify',
|
||||
'api5.yubico.com/wsapi/2.0/verify');
|
||||
|
||||
if ($this->_url_index>=count($url_list)) return false;
|
||||
else return $url_list[$this->_url_index++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets index to URL list
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function URLreset()
|
||||
{
|
||||
$this->_url_index=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another URLpart.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function addURLpart($URLpart)
|
||||
{
|
||||
$this->_url_list[]=$URLpart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last query sent to the server, if any.
|
||||
*
|
||||
* @return string Request to server
|
||||
* @access public
|
||||
*/
|
||||
function getLastQuery()
|
||||
{
|
||||
return $this->_lastquery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last data received from the server, if any.
|
||||
*
|
||||
* @return string Output from server
|
||||
* @access public
|
||||
*/
|
||||
function getLastResponse()
|
||||
{
|
||||
return $this->_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse input string into password, yubikey prefix,
|
||||
* ciphertext, and OTP.
|
||||
*
|
||||
* @param string Input string to parse
|
||||
* @param string Optional delimiter re-class, default is '[:]'
|
||||
* @return array Keyed array with fields
|
||||
* @access public
|
||||
*/
|
||||
function parsePasswordOTP($str, $delim = '[:]')
|
||||
{
|
||||
if (!preg_match("/^((.*)" . $delim . ")?" .
|
||||
"(([cbdefghijklnrtuv]{0,16})" .
|
||||
"([cbdefghijklnrtuv]{32}))$/i",
|
||||
$str, $matches)) {
|
||||
/* Dvorak? */
|
||||
if (!preg_match("/^((.*)" . $delim . ")?" .
|
||||
"(([jxe\.uidchtnbpygk]{0,16})" .
|
||||
"([jxe\.uidchtnbpygk]{32}))$/i",
|
||||
$str, $matches)) {
|
||||
return false;
|
||||
} else {
|
||||
$ret['otp'] = strtr($matches[3], "jxe.uidchtnbpygk", "cbdefghijklnrtuv");
|
||||
}
|
||||
} else {
|
||||
$ret['otp'] = $matches[3];
|
||||
}
|
||||
$ret['password'] = $matches[2];
|
||||
$ret['prefix'] = $matches[4];
|
||||
$ret['ciphertext'] = $matches[5];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/* TODO? Add functions to get parsed parts of server response? */
|
||||
|
||||
/**
|
||||
* Parse parameters from last response
|
||||
*
|
||||
* example: getParameters("timestamp", "sessioncounter", "sessionuse");
|
||||
*
|
||||
* @param array @parameters Array with strings representing
|
||||
* parameters to parse
|
||||
* @return array parameter array from last response
|
||||
* @access public
|
||||
*/
|
||||
function getParameters($parameters)
|
||||
{
|
||||
if ($parameters == null) {
|
||||
$parameters = array('timestamp', 'sessioncounter', 'sessionuse');
|
||||
}
|
||||
$param_array = array();
|
||||
foreach ($parameters as $param) {
|
||||
if(!preg_match("/" . $param . "=([0-9]+)/", $this->_response, $out)) {
|
||||
return PEAR::raiseError('Could not parse parameter ' . $param . ' from response');
|
||||
}
|
||||
$param_array[$param]=$out[1];
|
||||
}
|
||||
return $param_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify Yubico OTP against multiple URLs
|
||||
* Protocol specification 2.0 is used to construct validation requests
|
||||
*
|
||||
* @param string $token Yubico OTP
|
||||
* @param int $use_timestamp 1=>send request with ×tamp=1 to
|
||||
* get timestamp and session information
|
||||
* in the response
|
||||
* @param boolean $wait_for_all If true, wait until all
|
||||
* servers responds (for debugging)
|
||||
* @param string $sl Sync level in percentage between 0
|
||||
* and 100 or "fast" or "secure".
|
||||
* @param int $timeout Max number of seconds to wait
|
||||
* for responses
|
||||
* @return mixed PEAR error on error, true otherwise
|
||||
* @access public
|
||||
*/
|
||||
function verify($token, $use_timestamp=null, $wait_for_all=False,
|
||||
$sl=null, $timeout=null)
|
||||
{
|
||||
/* Construct parameters string */
|
||||
$ret = $this->parsePasswordOTP($token);
|
||||
if (!$ret) {
|
||||
return PEAR::raiseError('Could not parse Yubikey OTP');
|
||||
}
|
||||
$params = array('id'=>$this->_id,
|
||||
'otp'=>$ret['otp'],
|
||||
'nonce'=>md5(uniqid(rand())));
|
||||
/* Take care of protocol version 2 parameters */
|
||||
if ($use_timestamp) $params['timestamp'] = 1;
|
||||
if ($sl) $params['sl'] = $sl;
|
||||
if ($timeout) $params['timeout'] = $timeout;
|
||||
ksort($params);
|
||||
$parameters = '';
|
||||
foreach($params as $p=>$v) $parameters .= "&" . $p . "=" . $v;
|
||||
$parameters = ltrim($parameters, "&");
|
||||
|
||||
/* Generate signature. */
|
||||
if($this->_key <> "") {
|
||||
$signature = base64_encode(hash_hmac('sha1', $parameters,
|
||||
$this->_key, true));
|
||||
$signature = preg_replace('/\+/', '%2B', $signature);
|
||||
$parameters .= '&h=' . $signature;
|
||||
}
|
||||
|
||||
/* Generate and prepare request. */
|
||||
$this->_lastquery=null;
|
||||
$this->URLreset();
|
||||
$mh = curl_multi_init();
|
||||
$ch = array();
|
||||
while($URLpart=$this->getNextURLpart())
|
||||
{
|
||||
/* Support https. */
|
||||
if ($this->_https) {
|
||||
$query = "https://";
|
||||
} else {
|
||||
$query = "http://";
|
||||
}
|
||||
$query .= $URLpart . "?" . $parameters;
|
||||
|
||||
if ($this->_lastquery) { $this->_lastquery .= " "; }
|
||||
$this->_lastquery .= $query;
|
||||
|
||||
$handle = curl_init($query);
|
||||
curl_setopt($handle, CURLOPT_USERAGENT, "PEAR Auth_Yubico");
|
||||
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
|
||||
if (!$this->_httpsverify) {
|
||||
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
}
|
||||
curl_setopt($handle, CURLOPT_FAILONERROR, true);
|
||||
/* If timeout is set, we better apply it here as well
|
||||
in case the validation server fails to follow it.
|
||||
*/
|
||||
if ($timeout) curl_setopt($handle, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_multi_add_handle($mh, $handle);
|
||||
|
||||
$ch[(int)$handle] = $handle;
|
||||
}
|
||||
|
||||
/* Execute and read request. */
|
||||
$this->_response=null;
|
||||
$replay=False;
|
||||
$valid=False;
|
||||
do {
|
||||
/* Let curl do its work. */
|
||||
while (($mrc = curl_multi_exec($mh, $active))
|
||||
== CURLM_CALL_MULTI_PERFORM)
|
||||
;
|
||||
|
||||
while ($info = curl_multi_info_read($mh)) {
|
||||
if ($info['result'] == CURLE_OK) {
|
||||
|
||||
/* We have a complete response from one server. */
|
||||
|
||||
$str = curl_multi_getcontent($info['handle']);
|
||||
$cinfo = curl_getinfo ($info['handle']);
|
||||
|
||||
if ($wait_for_all) { # Better debug info
|
||||
$this->_response .= 'URL=' . $cinfo['url'] ."\n"
|
||||
. $str . "\n";
|
||||
}
|
||||
|
||||
if (preg_match("/status=([a-zA-Z0-9_]+)/", $str, $out)) {
|
||||
$status = $out[1];
|
||||
|
||||
/*
|
||||
* There are 3 cases.
|
||||
*
|
||||
* 1. OTP or Nonce values doesn't match - ignore
|
||||
* response.
|
||||
*
|
||||
* 2. We have a HMAC key. If signature is invalid -
|
||||
* ignore response. Return if status=OK or
|
||||
* status=REPLAYED_OTP.
|
||||
*
|
||||
* 3. Return if status=OK or status=REPLAYED_OTP.
|
||||
*/
|
||||
if (!preg_match("/otp=".$params['otp']."/", $str) ||
|
||||
!preg_match("/nonce=".$params['nonce']."/", $str)) {
|
||||
/* Case 1. Ignore response. */
|
||||
}
|
||||
elseif ($this->_key <> "") {
|
||||
/* Case 2. Verify signature first */
|
||||
$rows = explode("\r\n", trim($str));
|
||||
$response=array();
|
||||
while (list($key, $val) = each($rows)) {
|
||||
/* = is also used in BASE64 encoding so we only replace the first = by # which is not used in BASE64 */
|
||||
$val = preg_replace('/=/', '#', $val, 1);
|
||||
$row = explode("#", $val);
|
||||
$response[$row[0]] = $row[1];
|
||||
}
|
||||
|
||||
$parameters=array('nonce','otp', 'sessioncounter', 'sessionuse', 'sl', 'status', 't', 'timeout', 'timestamp');
|
||||
sort($parameters);
|
||||
$check=Null;
|
||||
foreach ($parameters as $param) {
|
||||
if (array_key_exists($param, $response)) {
|
||||
if ($check) $check = $check . '&';
|
||||
$check = $check . $param . '=' . $response[$param];
|
||||
}
|
||||
}
|
||||
|
||||
$checksignature =
|
||||
base64_encode(hash_hmac('sha1', utf8_encode($check),
|
||||
$this->_key, true));
|
||||
|
||||
if($response['h'] == $checksignature) {
|
||||
if ($status == 'REPLAYED_OTP') {
|
||||
if (!$wait_for_all) { $this->_response = $str; }
|
||||
$replay=True;
|
||||
}
|
||||
if ($status == 'OK') {
|
||||
if (!$wait_for_all) { $this->_response = $str; }
|
||||
$valid=True;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Case 3. We check the status directly */
|
||||
if ($status == 'REPLAYED_OTP') {
|
||||
if (!$wait_for_all) { $this->_response = $str; }
|
||||
$replay=True;
|
||||
}
|
||||
if ($status == 'OK') {
|
||||
if (!$wait_for_all) { $this->_response = $str; }
|
||||
$valid=True;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$wait_for_all && ($valid || $replay))
|
||||
{
|
||||
/* We have status=OK or status=REPLAYED_OTP, return. */
|
||||
foreach ($ch as $h) {
|
||||
curl_multi_remove_handle($mh, $h);
|
||||
curl_close($h);
|
||||
}
|
||||
curl_multi_close($mh);
|
||||
if ($replay) return PEAR::raiseError('REPLAYED_OTP');
|
||||
if ($valid) return true;
|
||||
return PEAR::raiseError($status);
|
||||
}
|
||||
|
||||
curl_multi_remove_handle($mh, $info['handle']);
|
||||
curl_close($info['handle']);
|
||||
unset ($ch[(int)$info['handle']]);
|
||||
}
|
||||
curl_multi_select($mh);
|
||||
}
|
||||
} while ($active);
|
||||
|
||||
/* Typically this is only reached for wait_for_all=true or
|
||||
* when the timeout is reached and there is no
|
||||
* OK/REPLAYED_REQUEST answer (think firewall).
|
||||
*/
|
||||
|
||||
foreach ($ch as $h) {
|
||||
curl_multi_remove_handle ($mh, $h);
|
||||
curl_close ($h);
|
||||
}
|
||||
curl_multi_close ($mh);
|
||||
|
||||
if ($replay) return PEAR::raiseError('REPLAYED_OTP');
|
||||
if ($valid) return true;
|
||||
return PEAR::raiseError('NO_VALID_ANSWER');
|
||||
}
|
||||
}
|
||||
?>
|
@ -3,18 +3,35 @@
|
||||
//ini_set("session.cookie_httponly", 1);
|
||||
session_start();
|
||||
if (isset($_POST["logout"])) {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
session_write_close();
|
||||
setcookie(session_name(),'',0,'/');
|
||||
if (isset($_SESSION["dual-login"])) {
|
||||
$_SESSION["mailcow_cc_username"] = $_SESSION["dual-login"]["username"];
|
||||
$_SESSION["mailcow_cc_role"] = $_SESSION["dual-login"]["role"];
|
||||
unset($_SESSION["dual-login"]);
|
||||
}
|
||||
else {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
session_write_close();
|
||||
setcookie(session_name(),'',0,'/');
|
||||
}
|
||||
}
|
||||
|
||||
require_once 'inc/vars.inc.php';
|
||||
|
||||
if (file_exists('./inc/vars.local.inc.php')) {
|
||||
include_once 'inc/vars.local.inc.php';
|
||||
}
|
||||
|
||||
// Yubi OTP API
|
||||
if (!empty($YUBI_API['ID']) && !empty($YUBI_API['KEY'])) {
|
||||
require_once 'inc/lib/Yubico.php';
|
||||
$yubi = new Auth_Yubico($YUBI_API['ID'], $YUBI_API['KEY']);
|
||||
}
|
||||
// U2F API
|
||||
require_once 'inc/lib/U2F.php';
|
||||
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
||||
$u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
|
||||
|
||||
// PDO
|
||||
$dsn = "$database_type:host=$database_host;dbname=$database_name";
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
@ -29,6 +46,7 @@ catch (PDOException $e) {
|
||||
<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>🐮 Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
|
||||
<?php
|
||||
}
|
||||
|
||||
$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
|
||||
setcookie('language', $DEFAULT_LANG);
|
||||
if (isset($_COOKIE['language'])) {
|
||||
@ -75,4 +93,4 @@ require_once 'lang/lang.en.php';
|
||||
include 'lang/lang.'.$_SESSION['mailcow_locale'].'.php';
|
||||
require_once 'inc/functions.inc.php';
|
||||
require_once 'inc/triggers.inc.php';
|
||||
init_db_schema();
|
||||
(!isset($_SESSION['mailcow_cc_username'])) ? init_db_schema() : null;
|
118
data/web/inc/tfa_modals.php
Normal file
118
data/web/inc/tfa_modals.php
Normal file
@ -0,0 +1,118 @@
|
||||
<div class="modal fade" id="YubiOTPModal" tabindex="-1" role="dialog" aria-labelledby="YubiOTPModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><b><?=$lang['tfa']['yubi_otp'];?></b></div>
|
||||
<div class="modal-body">
|
||||
<form role="form" method="post">
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
|
||||
<input type="text" name="otp_token" class="form-control" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
|
||||
<input type="hidden" name="tfa_method" value="yubi_otp">
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="set_tfa"><?=$lang['user']['save_changes'];?></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="U2FModal" tabindex="-1" role="dialog" aria-labelledby="U2FModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><b><?=$lang['tfa']['u2f'];?></b></div>
|
||||
<div class="modal-body">
|
||||
<form role="form" method="post" id="u2f_reg_form">
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
||||
</div>
|
||||
<hr>
|
||||
<p><?=$lang['tfa']['waiting_usb_register'];?></p>
|
||||
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
|
||||
<input type="hidden" name="token" id="u2f_register_data"/>
|
||||
<input type="hidden" name="tfa_method" value="u2f">
|
||||
<input type="hidden" name="set_tfa"/><br/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="DisableTFAModal" tabindex="-1" role="dialog" aria-labelledby="DisableTFAModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><b><?=$lang['tfa']['delete_tfa'];?></b></div>
|
||||
<div class="modal-body">
|
||||
<form role="form" method="post">
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
||||
<span class="input-group-btn">
|
||||
<input type="hidden" name="tfa_method" value="none">
|
||||
<button class="btn btn-danger" type="submit" name="set_tfa"><?=$lang['tfa']['delete_tfa'];?></button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if (isset($_SESSION['pending_tfa_method'])):
|
||||
$tfa_method = $_SESSION['pending_tfa_method'];
|
||||
?>
|
||||
<div class="modal fade" id="ConfirmTFAModal" tabindex="-1" role="dialog" aria-labelledby="ConfirmTFAModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><b><?=$lang['tfa'][$tfa_method];?></b></div>
|
||||
<div class="modal-body">
|
||||
<?php
|
||||
switch ($tfa_method) {
|
||||
case "yubi_otp":
|
||||
?>
|
||||
<form role="form" method="post">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
|
||||
<input type="text" name="token" id="token" class="form-control" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
|
||||
<input type="hidden" name="tfa_method" value="yubi_otp">
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="verify_tfa_login"><?=$lang['login']['login'];?></button>
|
||||
</form>
|
||||
<?php
|
||||
break;
|
||||
case "u2f":
|
||||
?>
|
||||
<form role="form" method="post" id="u2f_auth_form">
|
||||
<p><?=$lang['tfa']['waiting_usb_auth'];?></p>
|
||||
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
|
||||
<input type="hidden" name="token" id="u2f_auth_data"/>
|
||||
<input type="hidden" name="tfa_method" value="u2f">
|
||||
<input type="hidden" name="verify_tfa_login"/><br/>
|
||||
</form>
|
||||
<?php
|
||||
break;
|
||||
case "totp":
|
||||
?>
|
||||
<div class="empty"></div>
|
||||
<?php
|
||||
break;
|
||||
case "hotp":
|
||||
?>
|
||||
<div class="empty"></div>
|
||||
<?php
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
@ -1,4 +1,15 @@
|
||||
<?php
|
||||
if (isset($_POST["verify_tfa_login"])) {
|
||||
if (verify_tfa_login($_SESSION['pending_mailcow_cc_username'], $_POST["token"])) {
|
||||
$_SESSION['mailcow_cc_username'] = $_SESSION['pending_mailcow_cc_username'];
|
||||
$_SESSION['mailcow_cc_role'] = $_SESSION['pending_mailcow_cc_role'];
|
||||
unset($_SESSION['pending_mailcow_cc_username']);
|
||||
unset($_SESSION['pending_mailcow_cc_role']);
|
||||
unset($_SESSION['pending_tfa_method']);
|
||||
header("Location: /user.php");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
$login_user = strtolower(trim($_POST["login_user"]));
|
||||
$as = check_login($login_user, $_POST["pass_user"]);
|
||||
@ -17,100 +28,143 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
$_SESSION['mailcow_cc_role'] = "user";
|
||||
header("Location: /user.php");
|
||||
}
|
||||
else {
|
||||
elseif ($as != "pending") {
|
||||
unset($_SESSION['pending_mailcow_cc_username']);
|
||||
unset($_SESSION['pending_mailcow_cc_role']);
|
||||
unset($_SESSION['pending_tfa_method']);
|
||||
unset($_SESSION['mailcow_cc_username']);
|
||||
unset($_SESSION['mailcow_cc_role']);
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => $lang['danger']['login_failed']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||
if (isset($_POST["trigger_set_admin"])) {
|
||||
set_admin_account($_POST);
|
||||
if (isset($_GET["duallogin"])) {
|
||||
if (filter_var($_GET["duallogin"], FILTER_VALIDATE_EMAIL)) {
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :duallogin");
|
||||
$stmt->execute(array(':duallogin' => $_GET["duallogin"]));
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
if ($num_results != 0) {
|
||||
$_SESSION["dual-login"]["username"] = $_SESSION['mailcow_cc_username'];
|
||||
$_SESSION["dual-login"]["role"] = $_SESSION['mailcow_cc_role'];
|
||||
$_SESSION['mailcow_cc_username'] = $_GET["duallogin"];
|
||||
$_SESSION['mailcow_cc_role'] = "user";
|
||||
header("Location: /user.php");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST["edit_admin_account"])) {
|
||||
edit_admin_account($_POST);
|
||||
}
|
||||
if (isset($_POST["delete_dkim_record"])) {
|
||||
dkim_table("delete", $_POST);
|
||||
if (isset($_POST["dkim_delete_key"])) {
|
||||
dkim_delete_key($_POST);
|
||||
}
|
||||
if (isset($_POST["add_dkim_record"])) {
|
||||
dkim_table("add", $_POST);
|
||||
if (isset($_POST["dkim_add_key"])) {
|
||||
dkim_add_key($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_add_domain_admin"])) {
|
||||
if (isset($_POST["add_domain_admin"])) {
|
||||
add_domain_admin($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_delete_domain_admin"])) {
|
||||
if (isset($_POST["delete_domain_admin"])) {
|
||||
delete_domain_admin($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_edit_domain_admin"])) {
|
||||
edit_domain_admin($_POST);
|
||||
}
|
||||
}
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user") {
|
||||
if (isset($_POST["trigger_set_user_account"])) {
|
||||
set_user_account($_POST);
|
||||
if (isset($_POST["edit_user_account"])) {
|
||||
edit_user_account($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_set_spam_score"])) {
|
||||
set_spam_score($_POST);
|
||||
if (isset($_POST["mailbox_reset_eas"])) {
|
||||
mailbox_reset_eas($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_set_tagging_options"])) {
|
||||
tagging_options('set', $_POST);
|
||||
if (isset($_POST["edit_spam_score"])) {
|
||||
edit_spam_score($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_set_policy_list"])) {
|
||||
set_policy_list($_POST);
|
||||
if (isset($_POST["edit_delimiter_action"])) {
|
||||
edit_delimiter_action($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_set_tls_policy"])) {
|
||||
set_tls_policy($_POST);
|
||||
if (isset($_POST["add_policy_list_item"])) {
|
||||
add_policy_list_item($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_set_time_limited_aliases"])) {
|
||||
if (isset($_POST["delete_policy_list_item"])) {
|
||||
delete_policy_list_item($_POST);
|
||||
}
|
||||
if (isset($_POST["edit_tls_policy"])) {
|
||||
edit_tls_policy($_POST);
|
||||
}
|
||||
if (isset($_POST["add_syncjob"])) {
|
||||
add_syncjob($_POST);
|
||||
}
|
||||
if (isset($_POST["edit_syncjob"])) {
|
||||
edit_syncjob($_POST);
|
||||
}
|
||||
if (isset($_POST["delete_syncjob"])) {
|
||||
delete_syncjob($_POST);
|
||||
}
|
||||
if (isset($_POST["set_time_limited_aliases"])) {
|
||||
set_time_limited_aliases($_POST);
|
||||
}
|
||||
}
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
if (isset($_GET["js"])) {
|
||||
switch ($_GET["js"]) {
|
||||
case "remaining_specs":
|
||||
remaining_specs($_GET['domain'], $_GET['object'], "y");
|
||||
break;
|
||||
}
|
||||
if (isset($_POST["edit_domain_admin"])) {
|
||||
edit_domain_admin($_POST);
|
||||
}
|
||||
if (isset($_POST["trigger_mailbox_action"])) {
|
||||
switch ($_POST["trigger_mailbox_action"]) {
|
||||
case "adddomain":
|
||||
mailbox_add_domain($_POST);
|
||||
break;
|
||||
case "addalias":
|
||||
mailbox_add_alias($_POST);
|
||||
break;
|
||||
case "editalias":
|
||||
mailbox_edit_alias($_POST);
|
||||
break;
|
||||
case "addaliasdomain":
|
||||
mailbox_add_alias_domain($_POST);
|
||||
break;
|
||||
case "addmailbox":
|
||||
mailbox_add_mailbox($_POST);
|
||||
break;
|
||||
case "editdomain":
|
||||
mailbox_edit_domain($_POST);
|
||||
break;
|
||||
case "editmailbox":
|
||||
mailbox_edit_mailbox($_POST);
|
||||
break;
|
||||
case "deletedomain":
|
||||
mailbox_delete_domain($_POST);
|
||||
break;
|
||||
case "deletealias":
|
||||
mailbox_delete_alias($_POST);
|
||||
break;
|
||||
case "deletealiasdomain":
|
||||
mailbox_delete_alias_domain($_POST);
|
||||
break;
|
||||
case "editaliasdomain":
|
||||
mailbox_edit_alias_domain($_POST);
|
||||
break;
|
||||
case "deletemailbox":
|
||||
mailbox_delete_mailbox($_POST);
|
||||
break;
|
||||
}
|
||||
if (isset($_POST["set_tfa"])) {
|
||||
set_tfa($_POST);
|
||||
}
|
||||
if (isset($_POST["add_policy_list_item"])) {
|
||||
add_policy_list_item($_POST);
|
||||
}
|
||||
if (isset($_POST["delete_policy_list_item"])) {
|
||||
delete_policy_list_item($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_add_domain"])) {
|
||||
mailbox_add_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_add_alias"])) {
|
||||
mailbox_add_alias($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_add_alias_domain"])) {
|
||||
mailbox_add_alias_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_add_mailbox"])) {
|
||||
mailbox_add_mailbox($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_add_resource"])) {
|
||||
mailbox_add_resource($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_edit_alias"])) {
|
||||
mailbox_edit_alias($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_edit_domain"])) {
|
||||
mailbox_edit_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_edit_mailbox"])) {
|
||||
mailbox_edit_mailbox($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_edit_alias_domain"])) {
|
||||
mailbox_edit_alias_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_edit_resource"])) {
|
||||
mailbox_edit_resource($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_delete_domain"])) {
|
||||
mailbox_delete_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_delete_alias"])) {
|
||||
mailbox_delete_alias($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_delete_alias_domain"])) {
|
||||
mailbox_delete_alias_domain($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_delete_mailbox"])) {
|
||||
mailbox_delete_mailbox($_POST);
|
||||
}
|
||||
if (isset($_POST["mailbox_delete_resource"])) {
|
||||
mailbox_delete_resource($_POST);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
error_reporting(0);
|
||||
error_reporting(E_ERROR | E_WARNING);
|
||||
//error_reporting(E_ALL);
|
||||
|
||||
/*
|
||||
PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
|
||||
@ -33,4 +34,9 @@ $DEFAULT_LANG = "en";
|
||||
// simplex, slate, spacelab, superhero, united, yeti
|
||||
// See https://bootswatch.com/
|
||||
$DEFAULT_THEME = "lumen";
|
||||
|
||||
// If you want to use Yubico TFA methods, setup an ID and a key here: https://upgrade.yubico.com/getapikey/
|
||||
// Remember to override this value using vars.local.inc.php, do not change it here.
|
||||
$YUBI_API['ID'] = "";
|
||||
$YUBI_API['KEY'] = "";
|
||||
?>
|
||||
|
@ -2,13 +2,15 @@ $(document).ready(function() {
|
||||
// add.php
|
||||
// Get max. possible quota for a domain when domain field changes
|
||||
$('#addSelectDomain').on('change', function() {
|
||||
$.get("add.php", { js:"remaining_specs", domain:this.value, object:"new" }, function(data){
|
||||
if (data != '0') {
|
||||
$("#quotaBadge").html('max. ' + data + ' MiB');
|
||||
$('#addInputQuota').attr({"disabled": false, "value": "", "type": "number", "max": data});
|
||||
$.get("json_api.php", { action:"get_domain_details", object:this.value }, function(data){
|
||||
var result = jQuery.parseJSON( data );
|
||||
max_new_mailbox_quota = ( result.max_new_mailbox_quota / 1048576);
|
||||
if (max_new_mailbox_quota != '0') {
|
||||
$("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
|
||||
$('#addInputQuota').attr({"disabled": false, "value": "", "type": "number", "max": max_new_mailbox_quota});
|
||||
}
|
||||
else {
|
||||
$("#quotaBadge").html('max. ' + data + ' MiB');
|
||||
$("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
|
||||
$('#addInputQuota').attr({"disabled": true, "value": "", "type": "text", "value": "n/a"});
|
||||
}
|
||||
});
|
||||
|
@ -5,10 +5,12 @@ $(document).ready(function() {
|
||||
var rowCountDomain = $('#domaintable >tbody >#data').length;
|
||||
var rowCountMailbox = $('#mailboxtable >tbody >#data').length;
|
||||
var rowCountAlias = $('#aliastable >tbody >#data').length;
|
||||
var rowCountResource = $('#resourcetable >tbody >#data').length;
|
||||
$("#numRowsDomainAlias").text(rowCountDomainAlias);
|
||||
$("#numRowsDomain").text(rowCountDomain);
|
||||
$("#numRowsMailbox").text(rowCountMailbox);
|
||||
$("#numRowsAlias").text(rowCountAlias);
|
||||
$("#numRowsResource").text(rowCountResource);
|
||||
|
||||
// Filter table function
|
||||
$.fn.extend({
|
||||
|
651
data/web/js/u2f-api.js
Normal file
651
data/web/js/u2f-api.js
Normal file
@ -0,0 +1,651 @@
|
||||
// Copyright 2014-2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
/**
|
||||
* @fileoverview The U2F api.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/** Namespace for the U2F api.
|
||||
* @type {Object}
|
||||
*/
|
||||
var u2f = u2f || {};
|
||||
|
||||
/**
|
||||
* The U2F extension id
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||||
|
||||
/**
|
||||
* Message types for messsages to/from the extension
|
||||
* @const
|
||||
* @enum {string}
|
||||
*/
|
||||
u2f.MessageTypes = {
|
||||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||||
'U2F_SIGN_RESPONSE': 'u2f_sign_response'
|
||||
};
|
||||
|
||||
/**
|
||||
* Response status codes
|
||||
* @const
|
||||
* @enum {number}
|
||||
*/
|
||||
u2f.ErrorCodes = {
|
||||
'OK': 0,
|
||||
'OTHER_ERROR': 1,
|
||||
'BAD_REQUEST': 2,
|
||||
'CONFIGURATION_UNSUPPORTED': 3,
|
||||
'DEVICE_INELIGIBLE': 4,
|
||||
'TIMEOUT': 5
|
||||
};
|
||||
|
||||
/**
|
||||
* A message type for registration requests
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* signRequests: Array<u2f.SignRequest>,
|
||||
* registerRequests: ?Array<u2f.RegisterRequest>,
|
||||
* timeoutSeconds: ?number,
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.Request;
|
||||
|
||||
/**
|
||||
* A message for registration responses
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.Response;
|
||||
|
||||
/**
|
||||
* An error object for responses
|
||||
* @typedef {{
|
||||
* errorCode: u2f.ErrorCodes,
|
||||
* errorMessage: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.Error;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* keyHandle: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignRequest;
|
||||
|
||||
/**
|
||||
* Data object for a sign response.
|
||||
* @typedef {{
|
||||
* keyHandle: string,
|
||||
* signatureData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignResponse;
|
||||
|
||||
/**
|
||||
* Data object for a registration request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterRequest;
|
||||
|
||||
/**
|
||||
* Data object for a registration response.
|
||||
* @typedef {{
|
||||
* registrationData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterResponse;
|
||||
|
||||
|
||||
// Low level MessagePort API support
|
||||
|
||||
/**
|
||||
* Sets up a MessagePort to the U2F extension using the
|
||||
* available mechanisms.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
*/
|
||||
u2f.getMessagePort = function(callback) {
|
||||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||||
// The actual message here does not matter, but we need to get a reply
|
||||
// for the callback to run. Thus, send an empty signature request
|
||||
// in order to get a failure response.
|
||||
var msg = {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: []
|
||||
};
|
||||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// We are on a whitelisted origin and can talk directly
|
||||
// with the extension.
|
||||
u2f.getChromeRuntimePort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was available, but we couldn't message
|
||||
// the extension directly, use iframe
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
});
|
||||
} else if (u2f.isAndroidChrome_()) {
|
||||
u2f.getAuthenticatorPort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was not available at all, which is normal
|
||||
// when this origin doesn't have access to any extensions.
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on android based on the browser's useragent.
|
||||
* @private
|
||||
*/
|
||||
u2f.isAndroidChrome_ = function() {
|
||||
var userAgent = navigator.userAgent;
|
||||
return userAgent.indexOf('Chrome') != -1 &&
|
||||
userAgent.indexOf('Android') != -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects directly to the extension via chrome.runtime.connect
|
||||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getChromeRuntimePort_ = function(callback) {
|
||||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||||
{'includeTlsChannelId': true});
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the Authenticator app.
|
||||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getAuthenticatorPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedAuthenticatorPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||||
* @param {Port} port
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_ = function(port) {
|
||||
this.port_ = port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format a return a sign request.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.formatSignRequest_ =
|
||||
function(signRequests, timeoutSeconds, reqId) {
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: signRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Format a return a register request.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.formatRegisterRequest_ =
|
||||
function(signRequests, registerRequests, timeoutSeconds, reqId) {
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
signRequests: signRequests,
|
||||
registerRequests: registerRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Posts a message on the underlying channel.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
|
||||
this.port_.postMessage(message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||||
function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message' || name == 'onmessage') {
|
||||
this.port_.onMessage.addListener(function(message) {
|
||||
// Emulate a minimal MessageEvent object
|
||||
handler({'data': message});
|
||||
});
|
||||
} else {
|
||||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the Authenticator app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_ = function() {
|
||||
this.requestId_ = -1;
|
||||
this.requestObject_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the Authenticator intent.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
|
||||
var intentLocation = /** @type {string} */ (message);
|
||||
document.location = intentLocation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener =
|
||||
function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message') {
|
||||
var self = this;
|
||||
/* Register a callback to that executes when
|
||||
* chrome injects the response. */
|
||||
window.addEventListener(
|
||||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||||
} else {
|
||||
console.error('WrappedAuthenticatorPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when a response is received from the Authenticator.
|
||||
* @param function({data: Object}) callback
|
||||
* @param {Object} message message Object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||||
function(callback, message) {
|
||||
var messageObject = JSON.parse(message.data);
|
||||
var intentUrl = messageObject['intentURL'];
|
||||
|
||||
var errorCode = messageObject['errorCode'];
|
||||
var responseObject = null;
|
||||
if (messageObject.hasOwnProperty('data')) {
|
||||
responseObject = /** @type {Object} */ (
|
||||
JSON.parse(messageObject['data']));
|
||||
responseObject['requestId'] = this.requestId_;
|
||||
}
|
||||
|
||||
/* Sign responses from the authenticator do not conform to U2F,
|
||||
* convert to U2F here. */
|
||||
responseObject = this.doResponseFixups_(responseObject);
|
||||
callback({'data': responseObject});
|
||||
};
|
||||
|
||||
/**
|
||||
* Fixup the response provided by the Authenticator to conform with
|
||||
* the U2F spec.
|
||||
* @param {Object} responseData
|
||||
* @return {Object} the U2F compliant response object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.doResponseFixups_ =
|
||||
function(responseObject) {
|
||||
if (responseObject.hasOwnProperty('responseData')) {
|
||||
return responseObject;
|
||||
} else if (this.requestObject_['type'] != u2f.MessageTypes.U2F_SIGN_REQUEST) {
|
||||
// Only sign responses require fixups. If this is not a response
|
||||
// to a sign request, then an internal error has occurred.
|
||||
return {
|
||||
'type': u2f.MessageTypes.U2F_REGISTER_RESPONSE,
|
||||
'responseData': {
|
||||
'errorCode': u2f.ErrorCodes.OTHER_ERROR,
|
||||
'errorMessage': 'Internal error: invalid response from Authenticator'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Non-conformant sign response, do fixups. */
|
||||
var encodedChallengeObject = responseObject['challenge'];
|
||||
if (typeof encodedChallengeObject !== 'undefined') {
|
||||
var challengeObject = JSON.parse(atob(encodedChallengeObject));
|
||||
var serverChallenge = challengeObject['challenge'];
|
||||
var challengesList = this.requestObject_['signData'];
|
||||
var requestChallengeObject = null;
|
||||
for (var i = 0; i < challengesList.length; i++) {
|
||||
var challengeObject = challengesList[i];
|
||||
if (challengeObject['keyHandle'] == responseObject['keyHandle']) {
|
||||
requestChallengeObject = challengeObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var responseData = {
|
||||
'errorCode': responseObject['resultCode'],
|
||||
'keyHandle': responseObject['keyHandle'],
|
||||
'signatureData': responseObject['signature'],
|
||||
'clientData': encodedChallengeObject
|
||||
};
|
||||
return {
|
||||
'type': u2f.MessageTypes.U2F_SIGN_RESPONSE,
|
||||
'responseData': responseData,
|
||||
'requestId': responseObject['requestId']
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Base URL for intents to Authenticator.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||||
|
||||
/**
|
||||
* Format a return a sign request.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds (ignored for now)
|
||||
* @param {number} reqId
|
||||
* @return {string}
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.formatSignRequest_ =
|
||||
function(signRequests, timeoutSeconds, reqId) {
|
||||
if (!signRequests || signRequests.length == 0) {
|
||||
return null;
|
||||
}
|
||||
/* TODO(fixme): stash away requestId, as the authenticator app does
|
||||
* not return it for sign responses. */
|
||||
this.requestId_ = reqId;
|
||||
/* TODO(fixme): stash away the signRequests, to deal with the legacy
|
||||
* response format returned by the Authenticator app. */
|
||||
this.requestObject_ = {
|
||||
'type': u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
'signData': signRequests,
|
||||
'requestId': reqId,
|
||||
'timeout': timeoutSeconds
|
||||
};
|
||||
|
||||
var appId = signRequests[0]['appId'];
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.appId=' + encodeURIComponent(appId) +
|
||||
';S.eventId=' + reqId +
|
||||
';S.challenges=' +
|
||||
encodeURIComponent(
|
||||
JSON.stringify(this.getBrowserDataList_(signRequests))) + ';end';
|
||||
return intentUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the browser data objects from the challenge list
|
||||
* @param {Array} challenges list of challenges
|
||||
* @return {Array} list of browser data objects
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_
|
||||
.prototype.getBrowserDataList_ = function(challenges) {
|
||||
return challenges
|
||||
.map(function(challenge) {
|
||||
var browserData = {
|
||||
'typ': 'navigator.id.getAssertion',
|
||||
'challenge': challenge['challenge']
|
||||
};
|
||||
var challengeObject = {
|
||||
'challenge' : browserData,
|
||||
'keyHandle' : challenge['keyHandle']
|
||||
};
|
||||
return challengeObject;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Format a return a register request.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} enrollChallenges
|
||||
* @param {number} timeoutSeconds (ignored for now)
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.formatRegisterRequest_ =
|
||||
function(signRequests, enrollChallenges, timeoutSeconds, reqId) {
|
||||
if (!enrollChallenges || enrollChallenges.length == 0) {
|
||||
return null;
|
||||
}
|
||||
// Assume the appId is the same for all enroll challenges.
|
||||
var appId = enrollChallenges[0]['appId'];
|
||||
var registerRequests = [];
|
||||
for (var i = 0; i < enrollChallenges.length; i++) {
|
||||
var registerRequest = {
|
||||
'challenge': enrollChallenges[i]['challenge'],
|
||||
'version': enrollChallenges[i]['version']
|
||||
};
|
||||
if (enrollChallenges[i]['appId'] != appId) {
|
||||
// Only include the appId when it differs from the first appId.
|
||||
registerRequest['appId'] = enrollChallenges[i]['appId'];
|
||||
}
|
||||
registerRequests.push(registerRequest);
|
||||
}
|
||||
var registeredKeys = [];
|
||||
if (signRequests) {
|
||||
for (i = 0; i < signRequests.length; i++) {
|
||||
var key = {
|
||||
'keyHandle': signRequests[i]['keyHandle'],
|
||||
'version': signRequests[i]['version']
|
||||
};
|
||||
// Only include the appId when it differs from the appId that's
|
||||
// being registered now.
|
||||
if (signRequests[i]['appId'] != appId) {
|
||||
key['appId'] = signRequests[i]['appId'];
|
||||
}
|
||||
registeredKeys.push(key);
|
||||
}
|
||||
}
|
||||
var request = {
|
||||
'type': u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
'appId': appId,
|
||||
'registerRequests': registerRequests,
|
||||
'registeredKeys': registeredKeys,
|
||||
'requestId': reqId,
|
||||
'timeoutSeconds': timeoutSeconds
|
||||
};
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.request=' + encodeURIComponent(JSON.stringify(request)) +
|
||||
';end';
|
||||
/* TODO(fixme): stash away requestId, this is is not necessary for
|
||||
* register requests, but here to keep parity with sign.
|
||||
*/
|
||||
this.requestId_ = reqId;
|
||||
return intentUrl;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||||
* @param {function(MessagePort)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIframePort_ = function(callback) {
|
||||
// Create the iframe
|
||||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||||
iframe.setAttribute('style', 'display:none');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
var ready = function(message) {
|
||||
if (message.data == 'ready') {
|
||||
channel.port1.removeEventListener('message', ready);
|
||||
callback(channel.port1);
|
||||
} else {
|
||||
console.error('First event on iframe port was not "ready"');
|
||||
}
|
||||
};
|
||||
channel.port1.addEventListener('message', ready);
|
||||
channel.port1.start();
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
// Deliver the port to the iframe and initialize
|
||||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// High-level JS API
|
||||
|
||||
/**
|
||||
* Default extension response timeout in seconds.
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||||
|
||||
/**
|
||||
* A singleton instance for a MessagePort to the extension.
|
||||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||||
* @private
|
||||
*/
|
||||
u2f.port_ = null;
|
||||
|
||||
/**
|
||||
* Callbacks waiting for a port
|
||||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.waitingForPort_ = [];
|
||||
|
||||
/**
|
||||
* A counter for requestIds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
u2f.reqCounter_ = 0;
|
||||
|
||||
/**
|
||||
* A map from requestIds to client callbacks
|
||||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.callbackMap_ = {};
|
||||
|
||||
/**
|
||||
* Creates or retrieves the MessagePort singleton to use.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getPortSingleton_ = function(callback) {
|
||||
if (u2f.port_) {
|
||||
callback(u2f.port_);
|
||||
} else {
|
||||
if (u2f.waitingForPort_.length == 0) {
|
||||
u2f.getMessagePort(function(port) {
|
||||
u2f.port_ = port;
|
||||
u2f.port_.addEventListener('message',
|
||||
/** @type {function(Event)} */ (u2f.responseHandler_));
|
||||
|
||||
// Careful, here be async callbacks. Maybe.
|
||||
while (u2f.waitingForPort_.length)
|
||||
u2f.waitingForPort_.shift()(u2f.port_);
|
||||
});
|
||||
}
|
||||
u2f.waitingForPort_.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles response messages from the extension.
|
||||
* @param {MessageEvent.<u2f.Response>} message
|
||||
* @private
|
||||
*/
|
||||
u2f.responseHandler_ = function(message) {
|
||||
var response = message.data;
|
||||
var reqId = response['requestId'];
|
||||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||||
console.error('Unknown or missing requestId in response.');
|
||||
return;
|
||||
}
|
||||
var cb = u2f.callbackMap_[reqId];
|
||||
delete u2f.callbackMap_[reqId];
|
||||
cb(response['responseData']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sign = function(signRequests, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = port.formatSignRequest_(signRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.register = function(registerRequests, signRequests,
|
||||
callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = port.formatRegisterRequest_(
|
||||
signRequests, registerRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
@ -14,15 +14,20 @@ $(document).ready(function() {
|
||||
$(".passFields").slideUp();
|
||||
}
|
||||
});
|
||||
|
||||
// Show generate button after time selection
|
||||
$('#trigger_set_time_limited_aliases').hide();
|
||||
$('#generate_tla').hide();
|
||||
$('#validity').change(function(){
|
||||
$('#trigger_set_time_limited_aliases').show();
|
||||
$('#generate_tla').show();
|
||||
});
|
||||
|
||||
// Init Bootstrap Switch
|
||||
$.fn.bootstrapSwitch.defaults.onColor = 'success';
|
||||
$("[name='tls_out']").bootstrapSwitch();
|
||||
$("[name='tls_in']").bootstrapSwitch();
|
||||
|
||||
// Log modal
|
||||
$('#logModal').on('show.bs.modal', function(e) {
|
||||
var logText = $(e.relatedTarget).data('log-text');
|
||||
$(e.currentTarget).find('#logText').html('<pre style="background:none;font-size:11px;line-height:1.1;border:0px">' + logText + '</pre>');
|
||||
});
|
||||
});
|
57
data/web/json_api.php
Normal file
57
data/web/json_api.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
require_once 'inc/prerequisites.inc.php';
|
||||
error_reporting(E_ALL);
|
||||
if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_username'])) {
|
||||
if ($_GET['action'] && $_GET['object']) {
|
||||
$action = $_GET['action'];
|
||||
$object = $_GET['object'];
|
||||
switch ($action) {
|
||||
case "get_mailbox_details":
|
||||
$data = mailbox_get_mailbox_details($object);
|
||||
if (!$data || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode(mailbox_get_mailbox_details($object), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
break;
|
||||
case "get_domain_details":
|
||||
$data = mailbox_get_domain_details($object);
|
||||
if (!$data || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode(mailbox_get_domain_details($object), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
break;
|
||||
case "get_u2f_reg_challenge":
|
||||
if (
|
||||
($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin")
|
||||
&&
|
||||
($_SESSION["mailcow_cc_username"] == $object)
|
||||
) {
|
||||
$data = $u2f->getRegisterData(get_u2f_registrations($object));
|
||||
list($req, $sigs) = $data;
|
||||
$_SESSION['regReq'] = json_encode($req);
|
||||
echo 'var req = ' . json_encode($req) . '; var sigs = ' . json_encode($sigs) . ';';
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
case "get_u2f_auth_challenge":
|
||||
if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
|
||||
$reqs = json_encode($u2f->getAuthenticateData(get_u2f_registrations($object)));
|
||||
$_SESSION['authReq'] = $reqs;
|
||||
echo 'var req = ' . $reqs . ';';
|
||||
}
|
||||
else {
|
||||
echo '{}';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
echo '{}';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,13 +10,13 @@ $lang['footer']['restart_sogo'] = 'SOGo neustarten';
|
||||
$lang['footer']['restart_now'] = 'Jetzt neustarten';
|
||||
$lang['footer']['restart_sogo_info'] = 'Einige Änderungen an Domains benötigen einen Neustart SOGos. Hier können Sie SOGo neustarten.<br /><br /><b>Wichtig:</b> Ein korrekter Neustart SOGos kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.';
|
||||
$lang['dkim']['confirm'] = 'Sind Sie sicher?';
|
||||
$lang['danger']['dkim_not_found'] = 'DKIM-Record nicht gefunden';
|
||||
$lang['danger']['dkim_remove_failed'] = 'Kann DKIM-Record nicht entfernen';
|
||||
$lang['danger']['dkim_add_failed'] = 'Kann DKIM-Record nicht hinzufügen';
|
||||
$lang['danger']['dkim_not_found'] = 'DKIM-Key nicht gefunden';
|
||||
$lang['danger']['dkim_remove_failed'] = 'Kann DKIM-Key nicht entfernen';
|
||||
$lang['danger']['dkim_add_failed'] = 'Kann DKIM-Key nicht hinzufügen';
|
||||
$lang['danger']['dkim_domain_or_sel_invalid'] = 'DKIM-Domain oder -Selector nicht korrekt';
|
||||
$lang['danger']['dkim_key_length_invalid'] = 'DKIM Schlüssellänge ungültig';
|
||||
$lang['success']['dkim_removed'] = 'DKIM-Record wurde entfernt';
|
||||
$lang['success']['dkim_added'] = 'DKIM-Record wurde hinzugefügt';
|
||||
$lang['success']['dkim_removed'] = 'DKIM-Key wurde entfernt';
|
||||
$lang['success']['dkim_added'] = 'DKIM-Key wurde hinzugefügt';
|
||||
$lang['danger']['access_denied'] = 'Zugriff verweigert oder unvollständige/ungültige Daten';
|
||||
$lang['danger']['whitelist_from_invalid'] = 'Whitelist-Eintrag ist ungültig';
|
||||
$lang['danger']['domain_invalid'] = 'Domainname ist ungültig';
|
||||
@ -39,6 +39,8 @@ $lang['success']['alias_added'] = 'Alias-Adresse(n) wurden angelegt';
|
||||
$lang['success']['alias_modified'] = 'Änderungen an Alias %s wurden gespeichert';
|
||||
$lang['success']['aliasd_modified'] = 'Änderungen an Alias-Domain %s wurden gespeichert';
|
||||
$lang['success']['mailbox_modified'] = 'Änderungen an Mailbox %s wurden gespeichert';
|
||||
$lang['success']['resource_modified'] = "Änderungen an Ressource %s wurden gespeichert";
|
||||
$lang['success']['object_modified'] = "Änderungen an Objekt %s wurden gespeichert";
|
||||
$lang['success']['msg_size_saved'] = 'Limit wurde gesetzt';
|
||||
$lang['danger']['aliasd_not_found'] = 'Alias-Domain nicht gefunden';
|
||||
$lang['danger']['targetd_not_found'] = 'Ziel-Domain nicht gefunden';
|
||||
@ -54,28 +56,30 @@ $lang['danger']['exit_code_not_null'] = 'Fehler: Exit-Code ist %d';
|
||||
$lang['danger']['mailbox_not_available'] = 'Mailbox nicht verfügbar';
|
||||
$lang['danger']['username_invalid'] = 'Benutzername kann nicht verwendet werden';
|
||||
$lang['danger']['password_mismatch'] = 'Passwort-Wiederholung stimmt nicht überein';
|
||||
$lang['danger']['password_complexity'] = 'Passwort entspricht nicht den Vorgaben';
|
||||
$lang['danger']['password_complexity'] = 'Passwort entspricht nicht den Vorgaben (Klein- und Großschreibung und mindestens eine Ziffer, mindestens 6 Zeichen lang)';
|
||||
$lang['danger']['password_empty'] = 'Passwort darf nicht leer sein';
|
||||
$lang['danger']['login_failed'] = 'Anmeldung fehlgeschlagen';
|
||||
$lang['danger']['mailbox_invalid'] = 'Mailboxname ist ungültig';
|
||||
$lang['danger']['resource_invalid'] = 'Ressourcenname ist ungültig';
|
||||
$lang['danger']['description_invalid'] = 'Ressourcenbeschreibung ist ungültig';
|
||||
$lang['danger']['mailbox_invalid_suggest'] = 'Mailboxname ist ungültig, meinten Sie vielleicht "%s"?';
|
||||
$lang['info']['fetchmail_planned'] = 'Aufgabe zur Mailabholung wurde geplant. Bitte prüfen Sie den Vorgangsstatus zu einem späteren Zeitpunkt noch einmal.';
|
||||
$lang['danger']['fetchmail_source_empty'] = 'Bitte geben Sie einen Quell-Ordner an';
|
||||
$lang['danger']['fetchmail_dest_empty'] = 'Bitte geben Sie einen Ziel-Ordner an';
|
||||
$lang['danger']['is_alias'] = '%s lautet bereits eine Alias-Adresse';
|
||||
$lang['danger']['is_alias_or_mailbox'] = "Eine Mailbox oder ein Alias mit der Adresse %s ist bereits vorhanden";
|
||||
$lang['danger']['is_spam_alias'] = '%s lautet bereits eine Spam-Alias-Adresse';
|
||||
$lang['danger']['quota_not_0_not_numeric'] = 'Speicherplatz muss numerisch und >= 0 sein';
|
||||
$lang['danger']['domain_not_found'] = 'Domain nicht gefunden.';
|
||||
$lang['danger']['domain_not_found'] = 'Domain "%s" nicht gefunden.';
|
||||
$lang['danger']['max_mailbox_exceeded'] = 'Anzahl an Mailboxen überschritten (%d von %d)';
|
||||
$lang['danger']['mailbox_quota_exceeded'] = 'Speicherplatz überschreitet das Limit (max. %d MiB)';
|
||||
$lang['danger']['mailbox_quota_left_exceeded'] = 'Nicht genügend Speicherplatz vorhanden (Speicherplatz anwendbar: %d MiB)';
|
||||
$lang['success']['mailbox_added'] = 'Mailbox %s wurde angelegt';
|
||||
$lang['success']['resource_added'] = 'Ressource %s wurde angelegt';
|
||||
$lang['success']['domain_removed'] = 'Domain %s wurde entfernt';
|
||||
$lang['success']['alias_removed'] = 'Alias-Adresse %s wurde entfernt';
|
||||
$lang['success']['alias_domain_removed'] = 'Alias-Domain %s wurde entfernt';
|
||||
$lang['success']['domain_admin_removed'] = 'Domain-Administrator %s wurde entfernt';
|
||||
$lang['success']['mailbox_removed'] = 'Mailbox %s wurde entfernt';
|
||||
$lang['success']['eas_reset'] = "ActiveSync Gerät des Benutzers %s wurden zurückgesetzt";
|
||||
$lang['success']['resource_removed'] = 'Ressource %s wurde entfernt';
|
||||
$lang['danger']['max_quota_in_use'] = 'Mailbox Speicherplatzlimit muss größer oder gleich %d MiB sein';
|
||||
$lang['danger']['domain_quota_m_in_use'] = 'Domain Speicherplatzlimit muss größer oder gleich %d MiB sein';
|
||||
$lang['danger']['mailboxes_in_use'] = 'Maximale Anzahl an Mailboxen muss größer oder gleich %d sein';
|
||||
@ -84,7 +88,6 @@ $lang['danger']['sender_acl_invalid'] = 'Sender ACL Wert muss eine Adresse oder
|
||||
$lang['danger']['domain_not_empty'] = 'Kann nur leere Domains entfernen';
|
||||
$lang['warning']['spam_alias_temp_error'] = 'Kann zur Zeit keinen Spam-Alias erstellen, bitte versuchen Sie es später noch einmal.';
|
||||
$lang['danger']['spam_alias_max_exceeded'] = 'Maximale Anzahl an Spam-Alias-Adressen erreicht';
|
||||
$lang['danger']['fetchmail_active'] = 'Ein Vorgang zur Mailabholung ist bereits aktiv, bitte haben Sie etwas Geduld.';
|
||||
$lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an';
|
||||
$lang['user']['on'] = 'Ein';
|
||||
$lang['user']['off'] = 'Aus';
|
||||
@ -93,15 +96,16 @@ $lang['user']['user_settings'] = 'Benutzereinstellungen';
|
||||
$lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen';
|
||||
$lang['user']['mailbox_details'] = 'Mailbox-Details';
|
||||
$lang['user']['change_password'] = 'Passwort ändern';
|
||||
$lang['user']['new_password'] = 'Neues Passwort:';
|
||||
$lang['user']['new_password'] = 'Neues Passwort';
|
||||
$lang['user']['save_changes'] = 'Änderungen speichern';
|
||||
$lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen):';
|
||||
$lang['user']['new_password_repeat'] = 'Neues Passwort (Wiederholung):';
|
||||
$lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';
|
||||
$lang['user']['new_password_repeat'] = 'Neues Passwort (Wiederholung)';
|
||||
$lang['user']['new_password_description'] = 'Mindestanforderung: 6 Zeichen lang, Buchstaben und Zahlen.';
|
||||
$lang['user']['did_you_know'] = '<b>Wussten Sie schon?</b> Sie können Ihre E-Mail-Adresse mit Tags versehen, etwa "ich+<b>Privat</b>@example.com", um Nachrichten automatisch in einem Unterordner (Beispiel: "Privat") abzulegen.';
|
||||
$lang['user']['spam_aliases'] = 'Temporäre E-Mail Aliasse';
|
||||
$lang['user']['alias'] = 'Alias';
|
||||
$lang['user']['aliases'] = 'Aliasse';
|
||||
$lang['user']['domain_aliases'] = 'Domain-Alias Adressen';
|
||||
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
|
||||
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als';
|
||||
$lang['user']['aliases_send_as_all'] = 'Absender für folgende Domains nicht prüfen';
|
||||
@ -111,7 +115,9 @@ $lang['user']['alias_valid_until'] = 'Gültig bis';
|
||||
$lang['user']['alias_remove_all'] = 'Alle entfernen';
|
||||
$lang['user']['alias_time_left'] = 'Zeit verbleibend';
|
||||
$lang['user']['alias_full_date'] = 'd.m.Y, H:i:s T';
|
||||
$lang['user']['syncjob_full_date'] = 'd.m.Y, H:i:s T';
|
||||
$lang['user']['alias_select_validity'] = 'Bitte Gültigkeit auswählen';
|
||||
$lang['user']['sync_jobs'] = 'Sync Jobs';
|
||||
$lang['user']['hour'] = 'Stunde';
|
||||
$lang['user']['hours'] = 'Stunden';
|
||||
$lang['user']['day'] = 'Tag';
|
||||
@ -134,6 +140,7 @@ $lang['user']['spamfilter_yellow'] = 'Gelb: Die Nachricht ist vielleicht Spam, w
|
||||
$lang['user']['spamfilter_red'] = 'Rot: Die Nachricht ist eindeutig Spam und wird vom Server abgelehnt';
|
||||
$lang['user']['spamfilter_default_score'] = 'Standardwert:';
|
||||
$lang['user']['spamfilter_hint'] = 'Der erste Wert beschreibt den "low spam score", der zweite Wert den "high spam score".';
|
||||
$lang['user']['spamfilter_table_domain_policy'] = "n.v. (Domainrichtlinie)";
|
||||
|
||||
$lang['user']['tls_policy_warning'] = '<strong>Vorsicht:</strong> Entscheiden Sie sich unverschlüsselte Verbindungen abzulehnen, kann dies dazu führen, dass Kontakte Sie nicht mehr erreichen.<br />Nachrichten, die die Richtlinie nicht erfüllen, werden durch einen Hard-Fail im Mailsystem abgewiesen.';
|
||||
$lang['user']['tls_policy'] = 'Verschlüsselungsrichtlinie';
|
||||
@ -150,6 +157,22 @@ $lang['user']['tag_in_subject'] = 'In Betreff';
|
||||
$lang['user']['tag_help_explain'] = 'Als Unterordner: Es wird ein Ordner mit dem Namen des Tags unterhalb der Inbox erstellt ("INBOX/Facebook").<br />
|
||||
In Betreff: Der Name des Tags wird dem Betreff angefügt, etwa "[Facebook] Meine Neuigkeiten".';
|
||||
$lang['user']['tag_help_example'] = 'Beispiel für eine getaggte E-Mail-Adresse: ich<b>+Facebook</b>@example.org';
|
||||
$lang['user']['eas_reset'] = 'ActiveSync Geräte-Cache zurücksetzen';
|
||||
$lang['user']['eas_reset_now'] = 'Jetzt zurücksetzen';
|
||||
$lang['user']['eas_reset_help'] = 'In vielen Fällen kann ein ActiveSync Profil durch das Zurücksetzen des Caches repariert werden.<br /><b>Vorsicht:</b> Alle Elemente werden erneut heruntergeladen!';
|
||||
|
||||
$lang['user']['encryption'] = 'Verschlüsselung';
|
||||
$lang['user']['username'] = 'Benutzername';
|
||||
$lang['user']['password'] = 'Password';
|
||||
$lang['user']['last_run'] = 'Letzte Ausführung';
|
||||
$lang['user']['excludes'] = 'Ausschlüsse';
|
||||
$lang['user']['interval'] = 'Intervall';
|
||||
$lang['user']['active'] = 'Aktiv';
|
||||
$lang['user']['action'] = 'Aktion';
|
||||
$lang['user']['edit'] = 'Bearbeiten';
|
||||
$lang['user']['remove'] = 'Entfernen';
|
||||
$lang['user']['delete_now'] = 'Sofort löschen';
|
||||
$lang['user']['create_syncjob'] = 'Neuen Sync-Job erstellen';
|
||||
|
||||
$lang['start']['dashboard'] = '%s - Dashboard';
|
||||
$lang['start']['start_rc'] = 'Roundcube öffnen';
|
||||
@ -180,10 +203,16 @@ $lang['header']['mailboxes'] = 'Mailboxen';
|
||||
$lang['header']['user_settings'] = 'Benutzereinstellungen';
|
||||
$lang['header']['login'] = 'Anmeldung';
|
||||
$lang['header']['logged_in_as_logout'] = 'Eingeloggt als <b>%s</b> (abmelden)';
|
||||
$lang['header']['logged_in_as_logout_dual'] = 'Eingeloggt als <b>%s <span class="text-info">[%s]</span></b>';
|
||||
$lang['header']['locale'] = 'Sprache';
|
||||
$lang['mailbox']['domain'] = 'Domain';
|
||||
$lang['mailbox']['alias'] = 'Alias';
|
||||
$lang['mailbox']['aliases'] = 'Aliasse';
|
||||
$lang['mailbox']['multiple_bookings'] = 'Mehrfachbuchen';
|
||||
$lang['mailbox']['kind'] = 'Art';
|
||||
$lang['mailbox']['description'] = 'Beschreibung';
|
||||
$lang['mailbox']['resources'] = 'Ressourcen';
|
||||
$lang['mailbox']['resource_name'] = 'Ressourcenname';
|
||||
$lang['mailbox']['domains'] = 'Domains';
|
||||
$lang['mailbox']['mailboxes'] = 'Mailboxen';
|
||||
$lang['mailbox']['mailbox_quota'] = 'Max. Größe einer Mailbox';
|
||||
@ -206,10 +235,12 @@ $lang['mailbox']['msg_num'] = 'Anzahl Nachrichten';
|
||||
$lang['mailbox']['remove'] = 'Entfernen';
|
||||
$lang['mailbox']['edit'] = 'Bearbeiten';
|
||||
$lang['mailbox']['archive'] = 'Archiv-Zugriff';
|
||||
$lang['mailbox']['no_record'] = 'Kein Eintrag';
|
||||
$lang['mailbox']['no_record'] = 'Kein Eintrag für Objekt %s';
|
||||
$lang['mailbox']['no_record_single'] = 'Kein Eintrag';
|
||||
$lang['mailbox']['add_domain'] = 'Domain hinzufügen';
|
||||
$lang['mailbox']['add_domain_alias'] = 'Domain-Alias hinzufügen';
|
||||
$lang['mailbox']['add_mailbox'] = 'Mailbox hinzufügen';
|
||||
$lang['mailbox']['add_resource'] = 'Ressource hinzufügen';
|
||||
$lang['mailbox']['add_alias'] = 'Alias hinzufügen';
|
||||
|
||||
$lang['info']['no_action'] = 'Keine Aktion anwendbar';
|
||||
@ -219,14 +250,26 @@ $lang['delete']['remove_domain_warning'] = '<b>Warnung:</b> Sie entfernen die Do
|
||||
$lang['delete']['remove_domainalias_warning'] = '<b>Warnung:</b> Sie entfernen die Alias-Domain <b>%s</b>!';
|
||||
$lang['delete']['remove_domainadmin_warning'] = '<b>Warnung:</b> Sie entfernen den Domain-Administrator <b>%s</b>!';
|
||||
$lang['delete']['remove_alias_warning'] = '<b>Warnung:</b> Sie entfernen die Alias-Adresse <b>%s</b>!';
|
||||
$lang['delete']['remove_syncjob_warning'] = '<b>Warnung:</b> Sie entfernen einen Sync-Job des Benutzers <b>%s</b>!';
|
||||
$lang['delete']['remove_mailbox_warning'] = '<b>Warnung:</b> Sie entfernen die Mailbox <b>%s</b>!';
|
||||
$lang['delete']['remove_mailbox_details'] = 'Die Mailbox wird <b>vollständig und permanent</b> entfernt!';
|
||||
$lang['delete']['remove_resource_warning'] = '<b>Warnung:</b> Sie entfernen die Ressource <b>%s</b>!';
|
||||
$lang['delete']['remove_resource_details'] = 'Die Ressource wird <b>vollständig und permanent</b> entfernt!';
|
||||
$lang['delete']['remove_domain_details'] = 'Diese Aktion entfernt ebenfalls Domain-Aliasse.<br /><br /><b>Eine Domain muss leer sein, um entfernt zu werden.</b>';
|
||||
$lang['delete']['remove_syncjob_details'] = 'Objekte dieses Sync-Jobs werden nicht mehr vom entfernten Server abgeholt.';
|
||||
$lang['delete']['remove_alias_details'] = 'Benutzer werden keine Nachrichten mehr von dieser Adresse erhalten und versenden koennen!</b>';
|
||||
$lang['delete']['remove_button'] = 'Entfernen';
|
||||
$lang['delete']['previous'] = 'Vorherige Seite';
|
||||
|
||||
$lang['edit']['syncjob'] = 'Sync-Job bearbeiten';
|
||||
$lang['edit']['save'] = 'Änderungen speichern';
|
||||
$lang['edit']['username'] = 'Benutzername';
|
||||
$lang['edit']['hostname'] = 'Servername';
|
||||
$lang['edit']['encryption'] = 'Verschlüsselungsmethode';
|
||||
$lang['edit']['maxage'] = 'Maximales Alter in Tagen einer Nachricht, die kopiert werden soll</br ><small>(0 = alle Nachrichten kopieren)</small>';
|
||||
$lang['edit']['subfolder2'] = 'Ziel-Ordner<br /><small>(leer = kein Unterordner)</small>';
|
||||
$lang['edit']['mins_interval'] = 'Intervall (min)';
|
||||
$lang['edit']['exclude'] = 'Elemente ausschließen (Regex)';
|
||||
$lang['edit']['archive'] = 'Archiv-Zugriff';
|
||||
$lang['edit']['max_mailboxes'] = 'Max. Mailboxanzahl:';
|
||||
$lang['edit']['title'] = 'Objekt bearbeiten';
|
||||
@ -264,10 +307,25 @@ $lang['edit']['dkim_txt_value'] = 'TXT-Record Wert:';
|
||||
$lang['edit']['previous'] = 'Vorherige Seite';
|
||||
$lang['edit']['unchanged_if_empty'] = 'Unverändert, wenn leer';
|
||||
$lang['edit']['dont_check_sender_acl'] = 'Absender für Domain %s nicht prüfen';
|
||||
$lang['edit']['multiple_bookings'] = 'Mehrfaches Buchen';
|
||||
$lang['edit']['kind'] = 'Art';
|
||||
$lang['edit']['resource'] = 'Ressource';
|
||||
|
||||
$lang['add']['syncjob'] = 'Sync-Job erstellen';
|
||||
$lang['add']['syncjob_hint'] = 'Passwörter werden unverschlüsselt abgelegt!';
|
||||
$lang['add']['hostname'] = 'Servername';
|
||||
$lang['add']['username'] = 'Benutzername';
|
||||
$lang['add']['enc_method'] = 'Verschlüsselungsmethode';
|
||||
$lang['add']['maxage'] = 'Maximum age of messages that will be polled from remote (0 = ignore age)';
|
||||
$lang['add']['subfolder2'] = 'Sync into subfolder on destination';
|
||||
$lang['add']['mins_interval'] = 'Abrufintervall (Minuten)';
|
||||
$lang['add']['exclude'] = 'Elemente ausschließen (Regex)';
|
||||
$lang['add']['delete2duplicates'] = 'Lösche Duplikate im Ziel';
|
||||
|
||||
$lang['add']['title'] = 'Objekt anlegen';
|
||||
$lang['add']['domain'] = 'Domain';
|
||||
$lang['add']['active'] = 'Aktiv';
|
||||
$lang['add']['multiple_bookings'] = 'Mehrfaches Buchen möglich';
|
||||
$lang['add']['save'] = 'Änderungen speichern';
|
||||
$lang['add']['description'] = 'Beschreibung:';
|
||||
$lang['add']['max_aliases'] = 'Max. mögliche Aliasse:';
|
||||
@ -289,7 +347,10 @@ $lang['add']['alias_domain'] = 'Alias-Domain';
|
||||
$lang['add']['select'] = 'Bitte auswählen';
|
||||
$lang['add']['target_domain'] = 'Ziel-Domain:';
|
||||
$lang['add']['mailbox'] = 'Mailbox';
|
||||
$lang['add']['resource'] = 'Ressource';
|
||||
$lang['add']['kind'] = 'Art';
|
||||
$lang['add']['mailbox_username'] = 'Benutzername (linker Teil der E-Mail-Adresse):';
|
||||
$lang['add']['resource_name'] = 'Ressourcenname:';
|
||||
$lang['add']['full_name'] = 'Vor- und Zuname:';
|
||||
$lang['add']['quota_mb'] = 'Speicherplatz (MiB):';
|
||||
$lang['add']['select_domain'] = 'Bitte zuerst eine Domain auswählen';
|
||||
@ -310,11 +371,21 @@ $lang['login']['login'] = 'Anmelden';
|
||||
$lang['login']['previous'] = 'Vorherige Seite';
|
||||
$lang['login']['delayed'] = 'Login wurde zur Sicherheit um %s Sekunde/n verzögert.';
|
||||
|
||||
$lang['login']['tfa'] = 'Zwei-Faktor-Authentifizierung';
|
||||
$lang['login']['tfa_details'] = 'Bitte bestätigen Sie Ihr Einmalpasswort im folgenden Feld';
|
||||
$lang['login']['confirm'] = 'Bestätigen';
|
||||
$lang['login']['otp'] = 'Einmalpasswort';
|
||||
$lang['login']['trash_login'] = 'Login verwerfen';
|
||||
$lang['tfa']['tfa'] = "Two-Factor Authentication";
|
||||
$lang['tfa']['set_tfa'] = "Konfiguriere Two-Factor Authentication Methode";
|
||||
$lang['tfa']['yubi_otp'] = "Yubico OTP Authentifizierung";
|
||||
$lang['tfa']['u2f'] = "U2F Authentifizierung";
|
||||
$lang['tfa']['hotp'] = "HOTP Authentifizierung";
|
||||
$lang['tfa']['totp'] = "TOTP Authentifizierung";
|
||||
$lang['tfa']['none'] = "Deaktiviert";
|
||||
$lang['tfa']['delete_tfa'] = "Deaktiviere TFA";
|
||||
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
||||
$lang['tfa']['confirm'] = "Bestätigen";
|
||||
$lang['tfa']['otp'] = "Einmalpasswort";
|
||||
$lang['tfa']['trash_login'] = "Login verwerfen";
|
||||
$lang['tfa']['select'] = "Bitte auswählen";
|
||||
$lang['tfa']['waiting_usb_auth'] = "<i>Warte auf USB-Gerät...</i><br /><br />Bitte jetzt den vorgesehenen Taster des U2F USB-Gerätes berühren.";
|
||||
$lang['tfa']['waiting_usb_register'] = "<i>Warte auf USB-Gerät...</i><br /><br />Bitte zuerst das obere Passwortfeld ausfüllen und erst dann den vorgesehenen Taster des U2F USB-Gerätes berühren.";
|
||||
|
||||
$lang['admin']['search_domain_da'] = 'Domains durchsuchen';
|
||||
$lang['admin']['restrictions'] = 'Postifx Restriktionen';
|
||||
@ -340,9 +411,12 @@ $lang['admin']['msg_size_limit_details'] = 'Diese Einstellung wird Postfix und d
|
||||
$lang['admin']['save'] = 'Änderungen speichern';
|
||||
$lang['admin']['maintenance'] = 'Wartung und Information';
|
||||
$lang['admin']['sys_info'] = 'Systeminformation';
|
||||
$lang['admin']['dkim_add_key'] = 'DKIM-Record hinzufügen';
|
||||
$lang['admin']['dkim_keys'] = 'DKIM-Records';
|
||||
$lang['admin']['dkim_key_length'] = 'DKIM Schlüssellänge (Bits)';
|
||||
$lang['admin']['dkim_add_key'] = 'DKIM-Key hinzufügen';
|
||||
$lang['admin']['dkim_keys'] = 'DKIM-Keys';
|
||||
$lang['admin']['dkim_key_valid'] = 'Key gültig';
|
||||
$lang['admin']['dkim_key_unused'] = 'Key ohne Zuweisung';
|
||||
$lang['admin']['dkim_key_missing'] = 'Key fehlt';
|
||||
$lang['admin']['dkim_key_hint'] = 'Der Selector für DKIM-Keys lautet immer <code>dkim</code>.';
|
||||
$lang['admin']['add'] = 'Hinzufügen';
|
||||
$lang['admin']['configuration'] = 'Konfiguration';
|
||||
$lang['admin']['password'] = 'Passwort';
|
||||
|
@ -10,13 +10,13 @@ $lang['footer']['restart_sogo'] = 'Restart SOGo';
|
||||
$lang['footer']['restart_now'] = 'Restart now';
|
||||
$lang['footer']['restart_sogo_info'] = 'Some tasks, e.g. adding a domain, require you to restart SOGo to catch changes made in the mailcow UI.<br /><br /><b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
|
||||
$lang['dkim']['confirm'] = "Are you sure?";
|
||||
$lang['danger']['dkim_not_found'] = "DKIM record not found";
|
||||
$lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM record";
|
||||
$lang['danger']['dkim_add_failed'] = "Cannot add given DKIM record";
|
||||
$lang['danger']['dkim_not_found'] = "DKIM key not found";
|
||||
$lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM key";
|
||||
$lang['danger']['dkim_add_failed'] = "Cannot add given DKIM key";
|
||||
$lang['danger']['dkim_domain_or_sel_invalid'] = "DKIM domain or selector invalid";
|
||||
$lang['danger']['dkim_key_length_invalid'] = "DKIM key length invalid";
|
||||
$lang['success']['dkim_removed'] = "DKIM record has been removed";
|
||||
$lang['success']['dkim_added'] = "DKIM record has been saved";
|
||||
$lang['success']['dkim_removed'] = "DKIM key has been removed";
|
||||
$lang['success']['dkim_added'] = "DKIM key has been saved";
|
||||
$lang['danger']['access_denied'] = "Access denied or invalid form data";
|
||||
$lang['danger']['whitelist_from_invalid'] = "Whitelist entry invalid";
|
||||
$lang['danger']['domain_invalid'] = "Domain name is invalid";
|
||||
@ -41,6 +41,8 @@ $lang['success']['alias_added'] = "Alias address/es has/have been added";
|
||||
$lang['success']['alias_modified'] = "Changes to alias have been saved";
|
||||
$lang['success']['aliasd_modified'] = "Changes to alias domain have been saved";
|
||||
$lang['success']['mailbox_modified'] = "Changes to mailbox %s have been saved";
|
||||
$lang['success']['resource_modified'] = "Changes to mailbox %s have been saved";
|
||||
$lang['success']['object_modified'] = "Changes to object %s have been saved";
|
||||
$lang['success']['msg_size_saved'] = "Message size limit has been set";
|
||||
$lang['danger']['aliasd_not_found'] = "Alias domain not found";
|
||||
$lang['danger']['targetd_not_found'] = "Target domain not found";
|
||||
@ -56,14 +58,13 @@ $lang['danger']['exit_code_not_null'] = "Error: Exit code was %d";
|
||||
$lang['danger']['mailbox_not_available'] = "Mailbox not available";
|
||||
$lang['danger']['username_invalid'] = "Username cannot be used";
|
||||
$lang['danger']['password_mismatch'] = "Confirmation password is not identical";
|
||||
$lang['danger']['password_complexity'] = "Password does not meet requirements";
|
||||
$lang['danger']['password_complexity'] = "Password does not meet requirements (upper and lowercase letters and at least one number, min. 6 characters long)";
|
||||
$lang['danger']['password_empty'] = "Password must not be empty";
|
||||
$lang['danger']['login_failed'] = "Login failed";
|
||||
$lang['danger']['mailbox_invalid'] = "Mailbox name is invalid";
|
||||
$lang['danger']['description_invalid'] = 'Resource description is invalid';
|
||||
$lang['danger']['resource_invalid'] = "Resource name is invalid";
|
||||
$lang['danger']['mailbox_invalid_suggest'] = 'Mailbox name is invalid, did you mean to type "%s"?';
|
||||
$lang['info']['fetchmail_planned'] = "Task to fetch emails has been planned. Please check the process at a later time.";
|
||||
$lang['danger']['fetchmail_source_empty'] = "Please define a source folder";
|
||||
$lang['danger']['fetchmail_dest_empty'] = "Please define a target folder";
|
||||
$lang['danger']['is_alias'] = "%s is already known as an alias address";
|
||||
$lang['danger']['is_alias_or_mailbox'] = "%s is already known as an alias or a mailbox";
|
||||
$lang['danger']['is_spam_alias'] = "%s is already known as a spam alias address";
|
||||
@ -73,11 +74,14 @@ $lang['danger']['max_mailbox_exceeded'] = "Max. mailboxes exceeded (%d of %d)";
|
||||
$lang['danger']['mailbox_quota_exceeded'] = "Quota exceeds the domain limit (max. %d MiB)";
|
||||
$lang['danger']['mailbox_quota_left_exceeded'] = "Not enough space left (space left: %d MiB)";
|
||||
$lang['success']['mailbox_added'] = "Mailbox %s has been added";
|
||||
$lang['success']['resource_added'] = "Resource %s has been added";
|
||||
$lang['success']['domain_removed'] = "Domain %s has been removed";
|
||||
$lang['success']['alias_removed'] = "Alias-Adresse %s has been removed";
|
||||
$lang['success']['alias_domain_removed'] = "Alias domain %s has been removed";
|
||||
$lang['success']['domain_admin_removed'] = "Domain administrator %s has been removed";
|
||||
$lang['success']['mailbox_removed'] = "Mailbox %s has been removed";
|
||||
$lang['success']['eas_reset'] = "ActiveSync devices for user %s were reset";
|
||||
$lang['success']['resource_removed'] = "Resource %s has been removed";
|
||||
$lang['danger']['max_quota_in_use'] = "Mailbox quota must be greater or equal to %d MiB";
|
||||
$lang['danger']['domain_quota_m_in_use'] = "Domain quota must be greater or equal to %s MiB";
|
||||
$lang['danger']['mailboxes_in_use'] = "Max. mailboxes must be greater or equal to %d";
|
||||
@ -86,7 +90,6 @@ $lang['danger']['sender_acl_invalid'] = "Sender ACL value is invalid";
|
||||
$lang['danger']['domain_not_empty'] = "Cannot remove non-empty domain";
|
||||
$lang['warning']['spam_alias_temp_error'] = "Temporary error: Cannot add spam alias, please try again later.";
|
||||
$lang['danger']['spam_alias_max_exceeded'] = "Max. allowed spam alias addresses exceeded";
|
||||
$lang['danger']['fetchmail_active'] = "A process is already running, please wait for it to finish.";
|
||||
$lang['danger']['validity_missing'] = 'Please assign a period of validity';
|
||||
$lang['user']['on'] = "On";
|
||||
$lang['user']['off'] = "Off";
|
||||
@ -95,25 +98,28 @@ $lang['user']['user_settings'] = 'User settings';
|
||||
$lang['user']['mailbox_settings'] = 'Mailbox settings';
|
||||
$lang['user']['mailbox_details'] = 'Mailbox details';
|
||||
$lang['user']['change_password'] = 'Change password';
|
||||
$lang['user']['new_password'] = 'New password:';
|
||||
$lang['user']['new_password'] = 'New password';
|
||||
$lang['user']['save_changes'] = 'Save changes';
|
||||
$lang['user']['password_now'] = 'Current password (confirm changes):';
|
||||
$lang['user']['new_password_repeat'] = 'Confirmation password (repeat):';
|
||||
$lang['user']['password_now'] = 'Current password (confirm changes)';
|
||||
$lang['user']['new_password_repeat'] = 'Confirmation password (repeat)';
|
||||
$lang['user']['new_password_description'] = 'Requirement: 6 characters long, letters and numbers.';
|
||||
$lang['user']['did_you_know'] = '<b>Did you know?</b> You can use tags in your email address ("me+<b>privat</b>@example.com") to move messages to a folder automatically (example: "privat").';
|
||||
$lang['user']['spam_aliases'] = 'Temporary email aliases';
|
||||
$lang['user']['alias'] = 'Alias';
|
||||
$lang['user']['aliases'] = 'Aliases';
|
||||
$lang['user']['domain_aliases'] = 'Domain alias addresses';
|
||||
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
|
||||
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as';
|
||||
$lang['user']['aliases_send_as_all'] = 'Do not check sender access for following domains';
|
||||
$lang['user']['aliases_send_as_all'] = 'Do not check sender access for following domain/s';
|
||||
$lang['user']['alias_create_random'] = 'Generate random alias';
|
||||
$lang['user']['alias_extend_all'] = 'Extend aliases by 1 hour';
|
||||
$lang['user']['alias_valid_until'] = 'Valid until';
|
||||
$lang['user']['alias_remove_all'] = 'Remove all aliases';
|
||||
$lang['user']['alias_time_left'] = 'Time left';
|
||||
$lang['user']['alias_full_date'] = 'd.m.Y, H:i:s T';
|
||||
$lang['user']['syncjob_full_date'] = 'd.m.Y, H:i:s T';
|
||||
$lang['user']['alias_select_validity'] = 'Period of validity';
|
||||
$lang['user']['sync_jobs'] = 'Sync jobs';
|
||||
$lang['user']['hour'] = 'Hour';
|
||||
$lang['user']['hours'] = 'Hours';
|
||||
$lang['user']['day'] = 'Day';
|
||||
@ -136,12 +142,13 @@ $lang['user']['spamfilter_yellow'] = 'Yellow: this message may be spam, will be
|
||||
$lang['user']['spamfilter_red'] = 'Red: This message is spam and will be rejected by the server';
|
||||
$lang['user']['spamfilter_default_score'] = 'Default values:';
|
||||
$lang['user']['spamfilter_hint'] = 'The first value describes the "low spam score", the second represents the "high spam score".';
|
||||
$lang['user']['spamfilter_table_domain_policy'] = "n/a (domain policy)";
|
||||
|
||||
$lang['user']['tls_policy_warning'] = '<strong>Warning:</strong> If you decide to enforce encrypted mail transfer, you may lose emails.<br />Messages to not satisfy the policy will be bounced with a hard fail by the mail system.';
|
||||
$lang['user']['tls_policy'] = 'Encryption policy';
|
||||
$lang['user']['tls_enforce_in'] = 'Enforce TLS incoming';
|
||||
$lang['user']['tls_enforce_out'] = 'Enforce TLS outgoing';
|
||||
$lang['user']['no_record'] = 'No Record';
|
||||
$lang['user']['no_record'] = 'No record';
|
||||
|
||||
$lang['user']['misc_settings'] = 'Other profile settings';
|
||||
$lang['user']['misc_delete_profile'] = 'Other profile settings';
|
||||
@ -152,6 +159,22 @@ $lang['user']['tag_in_subject'] = 'In subject';
|
||||
$lang['user']['tag_help_explain'] = 'In subfolder: a new subfolder named after the tag will be created below INBOX ("INBOX/Facebook").<br />
|
||||
In subject: the tags name will be prepended to the mails subject, example: "[Facebook] Meine Neuigkeiten".';
|
||||
$lang['user']['tag_help_example'] = 'Example for a tagged email address: ich<b>+Facebook</b>@example.org';
|
||||
$lang['user']['eas_reset'] = 'Reset ActiveSync device cache';
|
||||
$lang['user']['eas_reset_now'] = 'Reset now';
|
||||
$lang['user']['eas_reset_help'] = 'In many cases a device cache reset will help to recover a broken ActiveSync profile.<br /><b>Attention:</b> All elements will be redownloaded!';
|
||||
|
||||
$lang['user']['encryption'] = 'Encyrption';
|
||||
$lang['user']['username'] = 'Username';
|
||||
$lang['user']['password'] = 'Password';
|
||||
$lang['user']['last_run'] = 'Last run';
|
||||
$lang['user']['excludes'] = 'Excludes';
|
||||
$lang['user']['interval'] = 'Interval';
|
||||
$lang['user']['active'] = 'Active';
|
||||
$lang['user']['action'] = 'Action';
|
||||
$lang['user']['edit'] = 'Edit';
|
||||
$lang['user']['remove'] = 'Remove';
|
||||
$lang['user']['delete_now'] = 'Remove now';
|
||||
$lang['user']['create_syncjob'] = 'Create new sync job';
|
||||
|
||||
$lang['start']['dashboard'] = '%s - dashboard';
|
||||
$lang['start']['start_rc'] = 'Open Roundcube';
|
||||
@ -182,12 +205,18 @@ $lang['header']['mailboxes'] = 'Mailboxes';
|
||||
$lang['header']['user_settings'] = 'User settings';
|
||||
$lang['header']['login'] = 'Login';
|
||||
$lang['header']['logged_in_as_logout'] = 'Logged in as <b>%s</b> (logout)';
|
||||
$lang['header']['logged_in_as_logout_dual'] = 'Logged in as <b>%s <span class="text-info">[%s]</span></b>';
|
||||
$lang['header']['locale'] = 'Language';
|
||||
$lang['mailbox']['domain'] = 'Domain';
|
||||
$lang['mailbox']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['mailbox']['kind'] = 'Kind';
|
||||
$lang['mailbox']['description'] = 'Description';
|
||||
$lang['mailbox']['alias'] = 'Alias';
|
||||
$lang['mailbox']['resource_name'] = 'Resource name';
|
||||
$lang['mailbox']['aliases'] = 'Aliases';
|
||||
$lang['mailbox']['domains'] = 'Domains';
|
||||
$lang['mailbox']['mailboxes'] = 'Mailboxes';
|
||||
$lang['mailbox']['resources'] = 'Resources';
|
||||
$lang['mailbox']['mailbox_quota'] = 'Max. size of a mailbox';
|
||||
$lang['mailbox']['domain_quota'] = 'Quota';
|
||||
$lang['mailbox']['active'] = 'Active';
|
||||
@ -208,37 +237,52 @@ $lang['mailbox']['msg_num'] = 'Message #';
|
||||
$lang['mailbox']['remove'] = 'Remove';
|
||||
$lang['mailbox']['edit'] = 'Edit';
|
||||
$lang['mailbox']['archive'] = 'Archive';
|
||||
$lang['mailbox']['no_record'] = 'No Record';
|
||||
$lang['mailbox']['no_record'] = 'No record for object %s';
|
||||
$lang['mailbox']['no_record_single'] = 'No record';
|
||||
$lang['mailbox']['add_domain'] = 'Add domain';
|
||||
$lang['mailbox']['add_domain_alias'] = 'Add domain alias';
|
||||
$lang['mailbox']['add_mailbox'] = 'Add mailbox';
|
||||
$lang['mailbox']['add_resource'] = 'Add resource';
|
||||
$lang['mailbox']['add_alias'] = 'Add alias';
|
||||
|
||||
$lang['info']['no_action'] = 'No action applicable';
|
||||
|
||||
$lang['delete']['title'] = 'Remove object';
|
||||
$lang['delete']['remove_domain_warning'] = '<b>Warning:</b> You are about to remove the domain <b>%s</b>!';
|
||||
$lang['delete']['remove_syncjob_warning'] = '<b>Warning:</b> You are about to remove a sync job for user <b>%s</b>!';
|
||||
$lang['delete']['remove_domainalias_warning'] = '<b>Warning:</b> You are about to remove the domain alias <b>%s</b>!';
|
||||
$lang['delete']['remove_domainadmin_warning'] = '<b>Warning:</b> You are about to remove the domain administrator <b>%s</b>!';
|
||||
$lang['delete']['remove_alias_warning'] = '<b>Warning:</b> You are about to remove the alias address <b>%s</b>!';
|
||||
$lang['delete']['remove_mailbox_warning'] = '<b>Warning:</b> You are about to remove the mailbox <b>%s</b>!';
|
||||
$lang['delete']['remove_mailbox_details'] = 'The mailbox will be <b>purged permanently</b>!';
|
||||
$lang['delete']['remove_resource_warning'] = '<b>Warning:</b> You are about to remove the resource <b>%s</b>!';
|
||||
$lang['delete']['remove_resource_details'] = 'The resource will be <b>purged permanently</b>!';
|
||||
$lang['delete']['remove_domain_details'] = 'This also removes domain aliases.<br /><br /><b>A domain must be empty to be removed.</b>';
|
||||
$lang['delete']['remove_syncjob_details'] = 'Objects from this sync job will not be pulled from the remote server anymore.';
|
||||
$lang['delete']['remove_alias_details'] = 'Users will no longer be able to receive mail for or send mail from this address.</b>';
|
||||
$lang['delete']['remove_button'] = 'Remove';
|
||||
$lang['delete']['previous'] = 'Previous page';
|
||||
|
||||
$lang['edit']['syncjob'] = 'Edit sync job';
|
||||
$lang['edit']['save'] = 'Save changes';
|
||||
$lang['edit']['username'] = 'Username';
|
||||
$lang['edit']['hostname'] = 'Hostname';
|
||||
$lang['edit']['encryption'] = 'Encryption';
|
||||
$lang['edit']['maxage'] = 'Maximum age of messages in days that will be polled from remote<br /><small>(0 = ignore age)</small>';
|
||||
$lang['edit']['subfolder2'] = 'Sync into subfolder on destination<br /><small>(empty = do not use subfolder)</small>';
|
||||
$lang['edit']['mins_interval'] = 'Interval (min)';
|
||||
$lang['edit']['exclude'] = 'Exclude objects (regex)';
|
||||
$lang['edit']['save'] = 'Save changes';
|
||||
$lang['edit']['archive'] = 'Archive access';
|
||||
$lang['edit']['max_mailboxes'] = 'Max. possible mailboxes:';
|
||||
$lang['edit']['max_mailboxes'] = 'Max. possible mailboxes';
|
||||
$lang['edit']['title'] = 'Edit object';
|
||||
$lang['edit']['target_address'] = 'Goto address/es <small>(comma-separated)</small>:';
|
||||
$lang['edit']['target_address'] = 'Goto address/es <small>(comma-separated)</small>';
|
||||
$lang['edit']['active'] = 'Active';
|
||||
$lang['edit']['target_domain'] = 'Target domain:';
|
||||
$lang['edit']['password'] = 'Password:';
|
||||
$lang['edit']['ratelimit'] = 'Outgoing rate limit/h:';
|
||||
$lang['edit']['target_domain'] = 'Target domain';
|
||||
$lang['edit']['password'] = 'Password';
|
||||
$lang['edit']['ratelimit'] = 'Outgoing rate limit/h';
|
||||
$lang['danger']['ratelimt_less_one'] = 'Outgoing rate limit/h must not be less than 1';
|
||||
$lang['edit']['password_repeat'] = 'Confirmation password (repeat):';
|
||||
$lang['edit']['password_repeat'] = 'Confirmation password (repeat)';
|
||||
$lang['edit']['domain_admin'] = 'Edit domain administrator';
|
||||
$lang['edit']['domain'] = 'Edit domain';
|
||||
$lang['edit']['alias_domain'] = 'Alias domain';
|
||||
@ -247,14 +291,14 @@ $lang['edit']['domains'] = 'Domains';
|
||||
$lang['edit']['destroy'] = 'Manual data input';
|
||||
$lang['edit']['alias'] = 'Edit alias';
|
||||
$lang['edit']['mailbox'] = 'Edit mailbox';
|
||||
$lang['edit']['description'] = 'Description:';
|
||||
$lang['edit']['max_aliases'] = 'Max. aliases:';
|
||||
$lang['edit']['max_quota'] = 'Max. quota per mailbox (MiB):';
|
||||
$lang['edit']['domain_quota'] = 'Domain quota:';
|
||||
$lang['edit']['backup_mx_options'] = 'Backup MX options:';
|
||||
$lang['edit']['description'] = 'Description';
|
||||
$lang['edit']['max_aliases'] = 'Max. aliases';
|
||||
$lang['edit']['max_quota'] = 'Max. quota per mailbox (MiB)';
|
||||
$lang['edit']['domain_quota'] = 'Domain quota';
|
||||
$lang['edit']['backup_mx_options'] = 'Backup MX options';
|
||||
$lang['edit']['relay_domain'] = 'Relay domain';
|
||||
$lang['edit']['relay_all'] = 'Relay all recipients';
|
||||
$lang['edit']['dkim_signature'] = 'DKIM signature:';
|
||||
$lang['edit']['dkim_signature'] = 'DKIM signature';
|
||||
$lang['edit']['dkim_record_info'] = '<small>Please add a TXT record with the given value to your DNS settings.</small>';
|
||||
$lang['edit']['relay_all_info'] = '<small>If you choose <b>not</b> to relay all recipients, you will need to add a ("blind") mailbox for every single recipient that should be relayed.</small>';
|
||||
$lang['edit']['full_name'] = 'Full name';
|
||||
@ -266,13 +310,29 @@ $lang['edit']['dkim_txt_value'] = 'TXT record value:';
|
||||
$lang['edit']['previous'] = 'Previous page';
|
||||
$lang['edit']['unchanged_if_empty'] = 'If unchanged leave blank';
|
||||
$lang['edit']['dont_check_sender_acl'] = 'Do not check sender for domain %s';
|
||||
$lang['edit']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['edit']['kind'] = 'Kind';
|
||||
$lang['edit']['resource'] = 'Resource';
|
||||
|
||||
$lang['add']['syncjob'] = 'Add sync job';
|
||||
$lang['add']['syncjob_hint'] = 'Be aware that passwords need to be saved plain-text!';
|
||||
$lang['add']['hostname'] = 'Hostname';
|
||||
$lang['add']['username'] = 'Username';
|
||||
$lang['add']['enc_method'] = 'Encryption method';
|
||||
$lang['add']['mins_interval'] = 'Polling interval (minutes)';
|
||||
$lang['add']['maxage'] = 'Maximum age of messages that will be polled from remote (0 = ignore age)';
|
||||
$lang['add']['subfolder2'] = 'Sync into subfolder on destination';
|
||||
$lang['add']['exclude'] = 'Exclude objects (regex)';
|
||||
$lang['add']['delete2duplicates'] = 'Delete duplicates on destination';
|
||||
|
||||
$lang['add']['title'] = 'Add object';
|
||||
$lang['add']['domain'] = 'Domain';
|
||||
$lang['add']['active'] = 'Active';
|
||||
$lang['add']['multiple_bookings'] = 'Multiple bookings';
|
||||
$lang['add']['save'] = 'Save changes';
|
||||
$lang['add']['description'] = 'Description:';
|
||||
$lang['add']['max_aliases'] = 'Max. possible aliases:';
|
||||
$lang['add']['resource_name'] = 'Resource name';
|
||||
$lang['add']['max_mailboxes'] = 'Max. possible mailboxes:';
|
||||
$lang['add']['mailbox_quota_m'] = 'Max. quota per mailbox (MiB):';
|
||||
$lang['add']['domain_quota_m'] = 'Total domain quota (MiB):';
|
||||
@ -291,6 +351,8 @@ $lang['add']['alias_domain'] = 'Alias domain';
|
||||
$lang['add']['select'] = 'Please select...';
|
||||
$lang['add']['target_domain'] = 'Target domain:';
|
||||
$lang['add']['mailbox'] = 'Mailbox';
|
||||
$lang['add']['resource'] = 'Resource';
|
||||
$lang['add']['kind'] = 'Kind';
|
||||
$lang['add']['mailbox_username'] = 'Username (left part of an email address):';
|
||||
$lang['add']['full_name'] = 'Full name:';
|
||||
$lang['add']['quota_mb'] = 'Quota (MiB):';
|
||||
@ -312,11 +374,21 @@ $lang['login']['login'] = 'Login';
|
||||
$lang['login']['previous'] = "Previous page";
|
||||
$lang['login']['delayed'] = 'Login was delayed by %s seconds.';
|
||||
|
||||
$lang['login']['tfa'] = "Two-factor authentication";
|
||||
$lang['login']['tfa_details'] = "Please confirm your one-time password in the below field";
|
||||
$lang['login']['confirm'] = "Confirm";
|
||||
$lang['login']['otp'] = "One-time password";
|
||||
$lang['login']['trash_login'] = "Trash login";
|
||||
$lang['tfa']['tfa'] = "Two-factor authentication";
|
||||
$lang['tfa']['set_tfa'] = "Set two-factor authentication method";
|
||||
$lang['tfa']['yubi_otp'] = "Yubico OTP authentication";
|
||||
$lang['tfa']['u2f'] = "U2F authentication";
|
||||
$lang['tfa']['hotp'] = "HOTP authentication";
|
||||
$lang['tfa']['totp'] = "TOTP authentication";
|
||||
$lang['tfa']['none'] = "Deaktiviert";
|
||||
$lang['tfa']['delete_tfa'] = "Disable TFA";
|
||||
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
||||
$lang['tfa']['confirm'] = "Confirm";
|
||||
$lang['tfa']['otp'] = "One-time password";
|
||||
$lang['tfa']['trash_login'] = "Trash login";
|
||||
$lang['tfa']['select'] = "Please select";
|
||||
$lang['tfa']['waiting_usb_auth'] = "<i>Waiting for USB device...</i><br /><br />Please tap the button on your U2F USB device now.";
|
||||
$lang['tfa']['waiting_usb_register'] = "<i>Waiting for USB device...</i><br /><br />Please enter your password above and confirm your U2F registration by tapping the button on your U2F USB device.";
|
||||
|
||||
$lang['admin']['search_domain_da'] = 'Search domains';
|
||||
$lang['admin']['restrictions'] = 'Postifx Restrictions';
|
||||
@ -340,6 +412,10 @@ $lang['admin']['privacy_anon_mail'] = 'Anonymize outgoing mail';
|
||||
$lang['admin']['dkim_txt_name'] = 'TXT record name:';
|
||||
$lang['admin']['dkim_txt_value'] = 'TXT record value:';
|
||||
$lang['admin']['dkim_key_length'] = 'DKIM key length (bits)';
|
||||
$lang['admin']['dkim_key_valid'] = 'Key valid';
|
||||
$lang['admin']['dkim_key_unused'] = 'Key unused';
|
||||
$lang['admin']['dkim_key_missing'] = 'Key missing';
|
||||
$lang['admin']['dkim_key_hint'] = 'Selector for DKIM keys is always <code>dkim</code>.';
|
||||
$lang['admin']['previous'] = 'Previous page';
|
||||
$lang['admin']['quota_mb'] = 'Quota (MiB):';
|
||||
$lang['admin']['sender_acl'] = 'Allow to send as:';
|
||||
@ -349,8 +425,8 @@ $lang['admin']['msg_size_limit_details'] = 'Applying a new limit will reload Pos
|
||||
$lang['admin']['save'] = 'Save changes';
|
||||
$lang['admin']['maintenance'] = 'Maintenance and Information';
|
||||
$lang['admin']['sys_info'] = 'System information';
|
||||
$lang['admin']['dkim_add_key'] = 'Add DKIM record';
|
||||
$lang['admin']['dkim_keys'] = 'DKIM records';
|
||||
$lang['admin']['dkim_add_key'] = 'Add DKIM key';
|
||||
$lang['admin']['dkim_keys'] = 'DKIM keys';
|
||||
$lang['admin']['add'] = 'Add';
|
||||
$lang['admin']['configuration'] = 'Configuration';
|
||||
$lang['admin']['password'] = 'Password';
|
||||
@ -374,5 +450,5 @@ $lang['admin']['invalid_max_msg_size'] = 'Invalid max. message size';
|
||||
$lang['admin']['site_not_found'] = 'Cannot locate mailcow site configuration';
|
||||
$lang['admin']['public_folder_empty'] = 'Public folder name must not be empty';
|
||||
$lang['admin']['set_rr_failed'] = 'Cannot set Postfix restrictions';
|
||||
$lang['admin']['no_record'] = 'No Record';
|
||||
$lang['admin']['no_record'] = 'No record';
|
||||
?>
|
||||
|
@ -4,7 +4,10 @@
|
||||
// Dutch language file
|
||||
*/
|
||||
$lang['footer']['loading'] = "Even geduld a.u.b. ...";
|
||||
$lang['getmail']['no_status'] = "Geen vorige status gevonden.";
|
||||
$lang['header']['restart_sogo'] = 'SOGo herstarten';
|
||||
$lang['footer']['restart_sogo'] = 'SOGo herstarten';
|
||||
$lang['footer']['restart_now'] = 'Nu opnieuw starten';
|
||||
$lang['footer']['restart_sogo_info'] = 'Sommige taken, zoals het toevoegen van een domein, vereisen een herstart van SOGo om de veranderingen door te voeren.<br /><br /><b>Belangrijk:</b> Het opnieuw opstarten kan een poos duren, wacht a.u.b. totdat dit volledig voltooid is.';
|
||||
$lang['dkim']['confirm'] = "Weet u het zeker?";
|
||||
$lang['danger']['dkim_not_found'] = "DKIM record niet gevonden.";
|
||||
$lang['danger']['dkim_remove_failed'] = "Kan geselecteerde DKIM record niet verwijderen.";
|
||||
@ -21,8 +24,8 @@ $lang['danger']['object_is_not_numeric'] = "%s is niet numeriek.";
|
||||
$lang['success']['domain_added'] = "Domein toegevoegd: %s.";
|
||||
$lang['danger']['alias_empty'] = "Aliasadres mag niet leeg blijven.";
|
||||
$lang['danger']['goto_empty'] = "Doeladres mag niet leeg blijven.";
|
||||
$lang['danger']['blacklist_exists'] = "Deze invoer staat op de zwarte lijst.";
|
||||
$lang['danger']['blacklist_from_invalid'] = "Zwarte lijst invoer heeft een ongeldig format.";
|
||||
$lang['danger']['policy_list_from_exists'] = "Deze invoer bestaat al.";
|
||||
$lang['danger']['policy_list_from_invalid'] = "Deze invoer heeft een ongeldig format.";
|
||||
$lang['danger']['whitelist_exists'] = "Deze invoer staat op de witte lijst.";
|
||||
$lang['danger']['whitelist_from_invalid'] = "Witte lijst invoer heeft een ongeldig format.";
|
||||
$lang['danger']['alias_invalid'] = "Aliasadres is ongeldig.";
|
||||
@ -90,10 +93,10 @@ $lang['user']['user_settings'] = 'Gebruikersinstellingen';
|
||||
$lang['user']['mailbox_settings'] = 'Postvakinstellingen';
|
||||
$lang['user']['mailbox_details'] = 'Postvakdetails';
|
||||
$lang['user']['change_password'] = 'Verander wachtwoord';
|
||||
$lang['user']['new_password'] = 'Nieuw wachtwoord:';
|
||||
$lang['user']['new_password'] = 'Nieuw wachtwoord';
|
||||
$lang['user']['save_changes'] = 'Wijzigingen opslaan';
|
||||
$lang['user']['password_now'] = 'Huidig wachtwoord (bevestig wijzigingen):';
|
||||
$lang['user']['new_password_repeat'] = 'Bevestig wachtwoord (herhalen):';
|
||||
$lang['user']['password_now'] = 'Huidig wachtwoord (bevestig wijzigingen)';
|
||||
$lang['user']['new_password_repeat'] = 'Bevestig wachtwoord (herhalen)';
|
||||
$lang['user']['new_password_description'] = 'Vereisten: 6 karakters lang, letters en nummers.';
|
||||
$lang['user']['did_you_know'] = '<b>Wist u dat?</b> U kunt tags in het e-mailadres gebruiken ("me+<b>prive</b>@voorbeeld.nl") om berichten automatisch naar een bijbehorende map te sturen (voorbeeld: "prive").';
|
||||
$lang['user']['spam_aliases'] = 'Tijdelijk e-mailadres';
|
||||
@ -120,6 +123,7 @@ $lang['user']['spamfilter_table_rule'] = 'Regel';
|
||||
$lang['user']['spamfilter_table_action'] = 'Handeling';
|
||||
$lang['user']['spamfilter_table_empty'] = 'Geen gegevens om weer te geven.';
|
||||
$lang['user']['spamfilter_table_remove'] = 'verwijder';
|
||||
$lang['user']['spamfilter_table_add'] = 'Voeg item toe';
|
||||
$lang['user']['spamfilter_default_score'] = 'Spamscore:';
|
||||
$lang['user']['spamfilter_green'] = 'Groen: Dit bericht is geen spam.';
|
||||
$lang['user']['spamfilter_yellow'] = 'Geel: Dit bericht is mogelijk spam, zal worden gelabeled en verplaatst worden naar de Junk-map.';
|
||||
@ -135,7 +139,13 @@ $lang['user']['no_record'] = 'Geen vermelding.';
|
||||
|
||||
$lang['user']['misc_settings'] = 'Andere profielinstellingen';
|
||||
$lang['user']['misc_delete_profile'] = 'Andere profielinstellingen';
|
||||
$lang['start']['dashboard'] = '%s - dashboard';
|
||||
$lang['user']['tag_handling'] = 'Omgaan met e-mail tags';
|
||||
$lang['user']['tag_in_subfolder'] = 'In onderliggende map';
|
||||
$lang['user']['tag_in_subject'] = 'In onderwerp';
|
||||
$lang['user']['tag_help_explain'] = 'In onderliggende map: maakt onder INBOX een nieuwe map aan met de naam van de tag (bijv.: "INBOX/Facebook").<br />
|
||||
In onderwerp: de tag wordt vóór het oorspronkelijke e-mail onderwerp geplaatst (bijv.: "[Facebook] Mijn nieuws").';
|
||||
$lang['user']['tag_help_example'] = 'Voorbeeld van een e-mailadres met tag: ik<b>+Facebook</b>@voorbeeld.org';
|
||||
$lang['start']['dashboard'] = '%s - startpagina';
|
||||
$lang['start']['start_rc'] = 'Open Roundcube';
|
||||
$lang['start']['start_sogo'] = 'Open SOGo';
|
||||
$lang['start']['mailcow_apps_detail'] = 'Gebruik een mailcow app om toegang te hebben tot uw e-mails, kalender, contactpersonen en meer.';
|
||||
@ -280,6 +290,7 @@ $lang['add']['select_domain'] = 'Selecteer eerst een domein';
|
||||
$lang['add']['password'] = 'Wachtwoord:';
|
||||
$lang['add']['password_repeat'] = 'Bevestig wachtwoord (herhalen):';
|
||||
$lang['add']['previous'] = 'Vorige pagina';
|
||||
$lang['add']['restart_sogo_hint'] = 'SOGo dient opnieuw te worden gestart nadat een domein is toegevoegd!';
|
||||
|
||||
$lang['login']['title'] = 'Aanmelden';
|
||||
$lang['login']['administration'] = 'Beheer';
|
||||
|
@ -91,10 +91,10 @@ $lang['user']['user_settings'] = 'Configurações do usuário';
|
||||
$lang['user']['mailbox_settings'] = 'Configrações da conta';
|
||||
$lang['user']['mailbox_details'] = 'Detalhes da conta';
|
||||
$lang['user']['change_password'] = 'Alterar senha';
|
||||
$lang['user']['new_password'] = 'Nova senha:';
|
||||
$lang['user']['new_password'] = 'Nova senha';
|
||||
$lang['user']['save_changes'] = 'Salvar';
|
||||
$lang['user']['password_now'] = 'Senha atual (confirme a alteração):';
|
||||
$lang['user']['new_password_repeat'] = 'Confirmar senha (repetir):';
|
||||
$lang['user']['password_now'] = 'Senha atual (confirme a alteração)';
|
||||
$lang['user']['new_password_repeat'] = 'Confirmar senha (repetir)';
|
||||
$lang['user']['new_password_description'] = 'Requerido: mínimo de 6 characteres com letras e números.';
|
||||
$lang['user']['did_you_know'] = '<b>Você sabia?</b> Você pode usar tags no endereço de email ("conta+<b>privado</b>@example.com") para classificar as mensagens automaticamente para uma determinada pasta (exemplo: "privado").';
|
||||
$lang['user']['spam_aliases'] = 'Apelidos temporários';
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require_once "inc/prerequisites.inc.php";
|
||||
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") {
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
require_once "inc/header.inc.php";
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
?>
|
||||
@ -49,80 +49,32 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
`domain`,
|
||||
`aliases`,
|
||||
`mailboxes`,
|
||||
`maxquota` * 1048576 AS `maxquota`,
|
||||
`quota` * 1048576 AS `quota`,
|
||||
CASE `backupmx` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `backupmx`,
|
||||
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
|
||||
FROM `domain` WHERE
|
||||
`domain` IN (
|
||||
SELECT `domain` FROM `domain_admins` WHERE `username`= :username AND `active`='1'
|
||||
)
|
||||
OR 'admin'= :admin");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role'],
|
||||
));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if(!empty($rows)):
|
||||
while($row = array_shift($rows)):
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
|
||||
WHERE `domain`= :domain
|
||||
AND `address` NOT IN (
|
||||
SELECT `username` FROM `mailbox`)");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
COUNT(*) AS `count`,
|
||||
COALESCE(SUM(`quota`), '0') AS `quota`
|
||||
FROM `mailbox`
|
||||
WHERE `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$domains = mailbox_get_domains();
|
||||
if (!empty($domains)):
|
||||
foreach ($domains as $domain):
|
||||
$domaindata = mailbox_get_domain_details($domain);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($row['domain']);?></td>
|
||||
<td><?=intval($AliasData['count']);?> / <?=intval($row['aliases']);?></td>
|
||||
<td><?=$MailboxData['count'];?> / <?=$row['mailboxes'];?></td>
|
||||
<td><?=formatBytes(intval($row['maxquota']), 2);?></td>
|
||||
<td><?=formatBytes(intval($MailboxData['quota']), 2);?> / <?=formatBytes(intval($row['quota']));?></td>
|
||||
<td><?=htmlspecialchars($domaindata['domain_name']);?></td>
|
||||
<td><?=$domaindata['aliases_in_domain'];?> / <?=$domaindata['max_num_aliases_for_domain'];?></td>
|
||||
<td><?=$domaindata['mboxes_in_domain'];?> / <?=$domaindata['max_num_mboxes_for_domain'];?></td>
|
||||
<td><?=formatBytes($domaindata['max_quota_for_mbox']);?></td>
|
||||
<td><?=formatBytes($domaindata['quota_used_in_domain'], 2);?> / <?=formatBytes($domaindata['max_quota_for_domain'], 2);?></td>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<td><?=$row['backupmx'];?></td>
|
||||
<td><?=$domaindata['backupmx'];?></td>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<td><?=$row['active'];?></td>
|
||||
<td><?=$domaindata['active'];?></td>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?domain=<?=urlencode($row['domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?domain=<?=urlencode($row['domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
<a href="/edit.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
<?php
|
||||
@ -130,19 +82,19 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
?>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?domain=<?=urlencode($row['domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/edit.php?domain=<?=urlencode($domaindata['domain_name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endif;
|
||||
endwhile;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record_single'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
@ -162,91 +114,6 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?> <span class="badge" id="numRowsDomainAlias"></span></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="domainaliastable-filter" data-action="filter" data-filters="#domainaliastable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainaliastable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
|
||||
<th class="sort-table" style="min-width: 127px;"><?=$lang['mailbox']['target_domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
`alias_domain`,
|
||||
`target_domain`,
|
||||
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
|
||||
FROM `alias_domain`
|
||||
WHERE `target_domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :username
|
||||
AND `active`='1'
|
||||
)
|
||||
OR 'admin' = :admin");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role'],
|
||||
));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if(!empty($rows)):
|
||||
while($row = array_shift($rows)):
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($row['alias_domain']);?></td>
|
||||
<td><?=htmlspecialchars($row['target_domain']);?></td>
|
||||
<td><?=$row['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?aliasdomain=<?=urlencode($row['alias_domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?aliasdomain=<?=urlencode($row['alias_domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="4" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
@ -278,91 +145,45 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
`domain`.`backupmx`,
|
||||
`mailbox`.`username`,
|
||||
`mailbox`.`name`,
|
||||
CASE `mailbox`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
|
||||
`mailbox`.`domain`,
|
||||
`mailbox`.`quota`,
|
||||
`quota2`.`bytes`,
|
||||
`quota2`.`messages`
|
||||
FROM `mailbox`, `quota2`, `domain`
|
||||
WHERE (`mailbox`.`username` = `quota2`.`username`)
|
||||
AND (`domain`.`domain` = `mailbox`.`domain`)
|
||||
AND (`mailbox`.`domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username`= :username
|
||||
AND `active`='1'
|
||||
)
|
||||
OR 'admin' = :admin)");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role'],
|
||||
));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if(!empty($rows)):
|
||||
while($row = array_shift($rows)):
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$mailboxes = mailbox_get_mailboxes($domain);
|
||||
if (!empty($mailboxes)) {
|
||||
foreach ($mailboxes as $mailbox) {
|
||||
$mailboxdata = mailbox_get_mailbox_details($mailbox);
|
||||
?>
|
||||
<tr id="data">
|
||||
<?php
|
||||
if ($row['backupmx'] == "0"):
|
||||
?>
|
||||
<td><?=htmlspecialchars($row['username']);?></td>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<td><span data-toggle="tooltip" title="Relayed"><i class="glyphicon glyphicon-forward"></i> <?=htmlspecialchars($row['username']);?></span></td>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<td><?=htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');?></td>
|
||||
<td><?=htmlspecialchars($row['domain']);?></td>
|
||||
<td><?=formatBytes(intval($row['bytes']), 2);?> / <?=formatBytes(intval($row['quota']), 2);?></td>
|
||||
<td><?=($mailboxdata['is_relayed'] == "0") ? htmlspecialchars($mailboxdata['username']) : '<span data-toggle="tooltip" title="Relayed"><i class="glyphicon glyphicon-forward"></i>' . htmlspecialchars($mailboxdata['username']) . '</span>';?></td>
|
||||
<td><?=htmlspecialchars($mailboxdata['name'], ENT_QUOTES, 'UTF-8');?></td>
|
||||
<td><?=htmlspecialchars($mailboxdata['domain']);?></td>
|
||||
<td><?=formatBytes($mailboxdata['quota_used'], 2);?> / <?=formatBytes($mailboxdata['quota'], 2);?></td>
|
||||
<td style="min-width:120px;">
|
||||
<?php
|
||||
$percentInUse = round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||
if ($percentInUse >= 90) {
|
||||
$pbar = "progress-bar-danger";
|
||||
}
|
||||
elseif ($percentInUse >= 75) {
|
||||
$pbar = "progress-bar-warning";
|
||||
}
|
||||
else {
|
||||
$pbar = "progress-bar-success";
|
||||
}
|
||||
?>
|
||||
<div class="progress">
|
||||
<div class="progress-bar <?=$pbar;?>" role="progressbar" aria-valuenow="<?=$percentInUse;?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$percentInUse;?>%;">
|
||||
<?=$percentInUse;?>%
|
||||
<div class="progress-bar progress-bar-<?=$mailboxdata['percent_class'];?>" role="progressbar" aria-valuenow="<?=$mailboxdata['percent_in_use'];?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$mailboxdata['percent_in_use'];?>%;">
|
||||
<?=$mailboxdata['percent_in_use'];?>%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><?=$row['messages'];?></td>
|
||||
<td><?=$row['active'];?></td>
|
||||
<td><?=$mailboxdata['messages'];?></td>
|
||||
<td><?=$mailboxdata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?mailbox=<?=urlencode($row['username']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?mailbox=<?=urlencode($row['username']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
<a href="/edit.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
<?php if ($_SESSION['mailcow_cc_role'] == "admin"): ?>
|
||||
<a href="/index.php?duallogin=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@ -377,6 +198,145 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['resources'];?> <span class="badge" id="numRowsResource"></span></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?resource"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="resourcetable-filter" data-action="filter" data-filters="#resourcetable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="resourcetable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['description'];?></th>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['kind'];?></th>
|
||||
<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['multiple_bookings'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$resources = mailbox_get_resources($domain);
|
||||
if (!empty($resources)) {
|
||||
foreach ($resources as $resource) {
|
||||
$resourcedata = mailbox_get_resource_details($resource);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($resourcedata['description'], ENT_QUOTES, 'UTF-8');?></td>
|
||||
<td><?=$resourcedata['kind'];?></td>
|
||||
<td><?=htmlspecialchars($resourcedata['domain']);?></td>
|
||||
<td><?=$resourcedata['multiple_bookings'];?></td>
|
||||
<td><?=$resourcedata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?resource"><?=$lang['mailbox']['add_resource'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?> <span class="badge" id="numRowsDomainAlias"></span></h3>
|
||||
<div class="pull-right">
|
||||
<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
|
||||
<i class="glyphicon glyphicon-filter"></i>
|
||||
</span>
|
||||
<a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<input type="text" class="form-control" id="domainaliastable-filter" data-action="filter" data-filters="#domainaliastable" placeholder="Filter" />
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainaliastable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
|
||||
<th class="sort-table" style="min-width: 127px;"><?=$lang['mailbox']['target_domain'];?></th>
|
||||
<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
$alias_domains = mailbox_get_alias_domains($domain);
|
||||
if (!empty($alias_domains)) {
|
||||
foreach ($alias_domains as $alias_domain) {
|
||||
$aliasdomaindata = mailbox_get_alias_domain_details($alias_domain);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($aliasdomaindata['alias_domain']);?></td>
|
||||
<td><?=htmlspecialchars($aliasdomaindata['target_domain']);?></td>
|
||||
<td><?=$aliasdomaindata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
@ -405,76 +365,42 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
`address`,
|
||||
`goto`,
|
||||
`domain`,
|
||||
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
|
||||
FROM alias
|
||||
WHERE (
|
||||
`address` NOT IN (
|
||||
SELECT `username` FROM `mailbox`
|
||||
)
|
||||
AND `address` != `goto`
|
||||
) AND (`domain` IN (
|
||||
SELECT `domain` FROM `domain_admins`
|
||||
WHERE `username` = :username
|
||||
AND active='1'
|
||||
)
|
||||
OR 'admin' = :admin)");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':admin' => $_SESSION['mailcow_cc_role'],
|
||||
));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if(!empty($rows)):
|
||||
while($row = array_shift($rows)):
|
||||
foreach (array_merge(mailbox_get_domains(), mailbox_get_alias_domains()) as $domain) {
|
||||
$aliases = mailbox_get_aliases($domain);
|
||||
if (!empty($aliases)) {
|
||||
foreach ($aliases as $alias) {
|
||||
$aliasdata = mailbox_get_alias_details($alias);
|
||||
?>
|
||||
<tr id="data">
|
||||
<td>
|
||||
<?php
|
||||
if(!filter_var($row['address'], FILTER_VALIDATE_EMAIL)):
|
||||
?>
|
||||
<span class="glyphicon glyphicon-pushpin" aria-hidden="true"></span> Catch-all @<?=htmlspecialchars($row['domain']);?>
|
||||
<?php
|
||||
else:
|
||||
echo htmlspecialchars($row['address']);
|
||||
endif;
|
||||
?>
|
||||
<?= ($aliasdata['is_catch_all'] == "1") ? '<span class="glyphicon glyphicon-pushpin" aria-hidden="true"></span> Catch-all ' . htmlspecialchars($aliasdata['address']) : htmlspecialchars($aliasdata['address']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
foreach(explode(",", $row['goto']) as $goto) {
|
||||
foreach(explode(",", $aliasdata['goto']) as $goto) {
|
||||
echo nl2br(htmlspecialchars($goto.PHP_EOL));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?=htmlspecialchars($row['domain']);?></td>
|
||||
<td><?=$row['active'];?></td>
|
||||
<td><?=htmlspecialchars($aliasdata['domain']);?></td>
|
||||
<td><?=$aliasdata['active'];?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?alias=<?=urlencode($row['address']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?alias=<?=urlencode($row['address']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
<a href="/edit.php?alias=<?=urlencode($aliasdata['address']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
|
||||
<a href="/delete.php?alias=<?=urlencode($aliasdata['address']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="5" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
|
157
data/web/u2f_api.php
Normal file
157
data/web/u2f_api.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
require_once('inc/prerequisites.inc.php');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
|
||||
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
||||
$u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
|
||||
|
||||
function getRegs($username) {
|
||||
global $pdo;
|
||||
$sel = $pdo->prepare("select * from tfa where username = ?");
|
||||
$sel->execute(array($username));
|
||||
return $sel->fetchAll();
|
||||
}
|
||||
function addReg($username, $reg) {
|
||||
global $pdo;
|
||||
$ins = $pdo->prepare("INSERT INTO `tfa` (`username`, `keyHandle`, `publicKey`, `certificate`, `counter`) values (?, ?, ?, ?, ?)");
|
||||
$ins->execute(array($username, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
|
||||
}
|
||||
function updateReg($reg) {
|
||||
global $pdo;
|
||||
$upd = $pdo->prepare("update tfa set counter = ? where id = ?");
|
||||
$upd->execute(array($reg->counter, $reg->id));
|
||||
}
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<script src="js/u2f-api.js"></script>
|
||||
<?php
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ((empty($_POST['u2f_username'])) || (!isset($_POST['action']) && !isset($_POST['u2f_register_data']) && !isset($_POST['u2f_auth_data']))) {
|
||||
print_r($_POST);
|
||||
exit();
|
||||
}
|
||||
else {
|
||||
$username = $_POST['u2f_username'];
|
||||
if (isset($_POST['action'])) {
|
||||
switch($_POST['action']) {
|
||||
case 'register':
|
||||
try {
|
||||
$data = $u2f->getRegisterData(getRegs($username));
|
||||
list($req, $sigs) = $data;
|
||||
$_SESSION['regReq'] = json_encode($req);
|
||||
?>
|
||||
<script>
|
||||
var req = <?=json_encode($req);?>;
|
||||
var sigs = <?=json_encode($sigs);?>;
|
||||
var username = "<?=$username;?>";
|
||||
setTimeout(function() {
|
||||
console.log("Register: ", req);
|
||||
u2f.register([req], sigs, function(data) {
|
||||
var form = document.getElementById('u2f_form');
|
||||
var reg = document.getElementById('u2f_register_data');
|
||||
var user = document.getElementById('u2f_username');
|
||||
var status = document.getElementById('u2f_status');
|
||||
console.log("Register callback", data);
|
||||
if (data.errorCode && data.errorCode != 0) {
|
||||
var div = document.getElementById('u2f_return_code');
|
||||
div.innerHTML = 'Error code: ' + data.errorCode;
|
||||
return;
|
||||
}
|
||||
reg.value = JSON.stringify(data);
|
||||
user.value = username;
|
||||
status.value = "1";
|
||||
form.submit();
|
||||
});
|
||||
}, 1000);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
catch( Exception $e ) {
|
||||
echo "U2F error: " . $e->getMessage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'authenticate':
|
||||
try {
|
||||
$reqs = json_encode($u2f->getAuthenticateData(getRegs($username)));
|
||||
$_SESSION['authReq'] = $reqs;
|
||||
?>
|
||||
<script>
|
||||
var req = <?=$reqs;?>;
|
||||
var username = "<?=$username;?>";
|
||||
setTimeout(function() {
|
||||
console.log("sign: ", req);
|
||||
u2f.sign(req, function(data) {
|
||||
var form = document.getElementById('u2f_form');
|
||||
var auth = document.getElementById('u2f_auth_data');
|
||||
var user = document.getElementById('u2f_username');
|
||||
console.log("Authenticate callback", data);
|
||||
auth.value = JSON.stringify(data);
|
||||
user.value = username;
|
||||
form.submit();
|
||||
});
|
||||
}, 1000);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
catch (Exception $e) {
|
||||
echo "U2F error: " . $e->getMessage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!empty($_POST['u2f_register_data'])) {
|
||||
try {
|
||||
$reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($_POST['u2f_register_data']));
|
||||
addReg($username, $reg);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
echo "U2F error: " . $e->getMessage();
|
||||
}
|
||||
finally {
|
||||
echo "Success";
|
||||
$_SESSION['regReq'] = null;
|
||||
}
|
||||
}
|
||||
if (!empty($_POST['u2f_auth_data'])) {
|
||||
try {
|
||||
$reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), getRegs($username), json_decode($_POST['u2f_auth_data']));
|
||||
updateReg($reg);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
echo "U2F error: " . $e->getMessage();
|
||||
}
|
||||
finally {
|
||||
echo "Success";
|
||||
$_SESSION['authReq'] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="u2f_return_code"></div>
|
||||
<form method="POST" id="u2f_form">
|
||||
<input type="hidden" name="u2f_register_data" id="u2f_register_data"/>
|
||||
<input type="hidden" name="u2f_auth_data" id="u2f_auth_data"/>
|
||||
<input type="hidden" name="u2f_username" id="u2f_username"/><br/>
|
||||
<input type="hidden" name="u2f_status" id="u2f_status"/><br/>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<form method="POST" id="post_form">
|
||||
Username: <input name="u2f_username" id="u2f_username"/><br/><hr>
|
||||
Action: <br />
|
||||
<input value="register" name="action" type="radio"/> Register<br/>
|
||||
<input value="authenticate" name="action" type="radio"/> Authenticate<br/>
|
||||
<button type="submit">Submit!</button>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
@ -1,90 +1,108 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
|
||||
|
||||
/*
|
||||
/ DOMAIN ADMIN
|
||||
*/
|
||||
|
||||
require_once("inc/header.inc.php");
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
?>
|
||||
<div class="container">
|
||||
<h3><?=$lang['user']['user_settings'];?></h3>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['user']['user_settings'];?></div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=get_tfa()['pretty'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?></div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<select id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
||||
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
||||
<option value="none"><?=$lang['tfa']['none'];?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
|
||||
|
||||
/*
|
||||
/ USER
|
||||
*/
|
||||
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
|
||||
require_once("inc/header.inc.php");
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
$username = $_SESSION['mailcow_cc_username'];
|
||||
$get_tls_policy = get_tls_policy($_SESSION['mailcow_cc_username']);
|
||||
?>
|
||||
<div class="container">
|
||||
<h3><?=$lang['user']['mailbox_settings'];?></h3>
|
||||
<p class="help-block"><?=$lang['user']['did_you_know'];?></p>
|
||||
<h3><?=$lang['user']['user_settings'];?></h3>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['user']['mailbox_details'];?></div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" role="form" method="post" autocomplete="off">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="togglePwNew" id="togglePwNew"> <?=$lang['user']['change_password'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
|
||||
</div>
|
||||
<div class="passFields">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_new_pass"><?=$lang['user']['new_password'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" pattern=".{6,}" name="user_new_pass" id="user_new_pass" autocomplete="off" disabled="disabled" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_new_pass2"><?=$lang['user']['new_password_repeat'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" pattern=".{6,}" name="user_new_pass2" id="user_new_pass2" disabled="disabled" autocomplete="off" required>
|
||||
<p class="help-block"><?=$lang['user']['new_password_description'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_old_pass"><?=$lang['user']['password_now'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" name="user_old_pass" id="user_old_pass" autocomplete="off" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<button type="submit" name="trigger_set_user_account" class="btn btn-success btn-default"><?=$lang['user']['save_changes'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<hr>
|
||||
<?php // Get user information about aliases
|
||||
$get_user_object_info = user_object_info('get');?>
|
||||
$user_get_alias_details = user_get_alias_details($username);?>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=$get_user_object_info['aliases'];?></p>
|
||||
<p><?=$user_get_alias_details['aliases'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['domain_aliases'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=$user_get_alias_details['ad_alias'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=$get_user_object_info['aliases_also_send_as'];?></p>
|
||||
<p><?=$user_get_alias_details['aliases_also_send_as'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_send_as_all'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=$get_user_object_info['aliases_send_as_all'];?></p>
|
||||
<p><?=$user_get_alias_details['aliases_send_as_all'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['is_catch_all'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<p><?=$get_user_object_info['is_catch_all'];?></p>
|
||||
<p><?=$user_get_alias_details['is_catch_all'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<?php // Show tagging options ?>
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<?php $get_tagging_options = tagging_options('get');?>
|
||||
<?php $get_tagging_options = get_delimiter_action()['wants_tagged_subject'];?>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tag_handling'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<input type="hidden" name="trigger_set_tagging_options" value="1">
|
||||
<input type="hidden" name="edit_delimiter_action" value="1">
|
||||
<select name="tagged_mail_handler" class="selectpicker" onchange="this.form.submit()">
|
||||
<option value="subfolder" <?=($get_tagging_options == "0") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subfolder'];?></option>
|
||||
<option value="subject" <?=($get_tagging_options == "1") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subject'];?></option>
|
||||
@ -94,6 +112,16 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php // Rest EAS devices ?>
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['eas_reset'];?>:</div>
|
||||
<div class="col-md-9 col-xs-7">
|
||||
<button type="submit" name="mailbox_reset_eas" id="mailbox_reset_eas" value="1" class="btn btn-xs btn-default"><?=$lang['user']['eas_reset_now'];?></button>
|
||||
<p class="help-block"><?=$lang['user']['eas_reset_help'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -102,56 +130,61 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<li role="presentation" class="active"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab"><?=$lang['user']['spam_aliases'];?></a></li>
|
||||
<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab"><?=$lang['user']['spamfilter'];?></a></li>
|
||||
<li role="presentation"><a href="#TLSPolicy" aria-controls="TLSPolicy" role="tab" data-toggle="tab"><?=$lang['user']['tls_policy'];?></a></li>
|
||||
<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab"><?=$lang['user']['sync_jobs'];?></a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="SpamAliases">
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="timelimitedaliases">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 96px;"><?=$lang['user']['alias'];?></th>
|
||||
<th class="sort-table" style="min-width: 135px;"><?=$lang['user']['alias_valid_until'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<p><b><?=$lang['user']['alias'];?></b></p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p><b><?=$lang['user']['alias_valid_until'];?></b></p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p><b><?=$lang['user']['action'];?></b></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `address`,
|
||||
`goto`,
|
||||
`validity`
|
||||
FROM `spamalias`
|
||||
WHERE `goto` = :username
|
||||
AND `validity` >= :unixnow");
|
||||
$stmt->execute(array(':username' => $username, ':unixnow' => time()));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if(!empty($rows)):
|
||||
while ($row = array_shift($rows)):
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($row['address']);?></td>
|
||||
<td><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></td>
|
||||
</tr>
|
||||
<?php
|
||||
endwhile;
|
||||
$get_time_limited_aliases = get_time_limited_aliases($username);
|
||||
if (!empty($get_time_limited_aliases)):
|
||||
foreach ($get_time_limited_aliases as $row):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<p><?=htmlspecialchars($row['address']);?></p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></p>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<a class="text-danger" href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<input type="hidden" name="set_time_limited_aliases" value="delete">
|
||||
<input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<form class="form-inline" role="form" method="post">
|
||||
<a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-time"></span> + 1h</a>
|
||||
<input type="hidden" name="set_time_limited_aliases" value="extend">
|
||||
<input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="2" style="text-align: center; font-style: italic;"><?=$lang['user']['no_record'];?></td></tr>
|
||||
<div class="col-xs-12">
|
||||
<center><i><?=$lang['user']['no_record'];?></i></center>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<form class="form-horizontal" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-9">
|
||||
<select id="validity" name="validity" title="<?=$lang['user']['alias_select_validity'];?>">
|
||||
@ -161,16 +194,16 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<option value="168">1 <?=$lang['user']['week'];?></option>
|
||||
<option value="672">4 <?=$lang['user']['weeks'];?></option>
|
||||
</select>
|
||||
<button type="submit" id="trigger_set_time_limited_aliases" name="trigger_set_time_limited_aliases" value="generate" class="btn btn-success"><?=$lang['user']['alias_create_random'];?></button>
|
||||
<button type="submit" name="set_time_limited_aliases" id="generate_tla" value="generate" class="btn btn-success"><?=$lang['user']['alias_create_random'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button style="border-color:#f5f5f5;background:none;color:red" type="submit" name="trigger_set_time_limited_aliases" value="delete" class="btn btn-sm">
|
||||
<button type="submit" name="set_time_limited_aliases" value="deleteall" class="btn-danger btn btn-sm">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> <?=$lang['user']['alias_remove_all'];?>
|
||||
</button>
|
||||
<button style="border-color:#f5f5f5;background:none;color:grey" type="submit" name="trigger_set_time_limited_aliases" value="extend" class="btn btn-sm">
|
||||
<span class="glyphicon glyphicon-hourglass" aria-hidden="true"></span> <?=$lang['user']['alias_extend_all'];?>
|
||||
<button type="submit" name="set_time_limited_aliases" value="extendall" class="btn-default btn btn-sm">
|
||||
<span class="glyphicon glyphicon-time" aria-hidden="true"></span> <?=$lang['user']['alias_extend_all'];?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -189,7 +222,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
data-slider-range="true"
|
||||
data-slider-tooltip='always'
|
||||
data-slider-id="slider1"
|
||||
data-slider-value="[<?=get_spam_score($_SESSION['mailcow_cc_username']);?>]"
|
||||
data-slider-value="[<?=get_spam_score($username);?>]"
|
||||
data-slider-step="1" />
|
||||
<br /><br />
|
||||
<ul>
|
||||
@ -203,7 +236,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" id="trigger_set_spam_score" name="trigger_set_spam_score" class="btn btn-success"><?=$lang['user']['save_changes'];?></button>
|
||||
<button type="submit" id="edit_spam_score" name="edit_spam_score" class="btn btn-success"><?=$lang['user']['save_changes'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -217,49 +250,39 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
|
||||
</div>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND `object`= :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if (count($rows) == 0):
|
||||
$get_policy_list = get_policy_list($username);
|
||||
if (empty($get_policy_list['whitelist'])):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
while ($whitelistRow = array_shift($rows)):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$whitelistRow['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<input type="hidden" name="prefid" value="<?=$whitelistRow['prefid'];?>">
|
||||
<?php
|
||||
if ($whitelistRow['username'] != array_pop(explode('@', $username))):
|
||||
?>
|
||||
<input type="hidden" name="trigger_set_policy_list">
|
||||
<a href="#n" onclick="$(this).closest('form').submit()"><?=$lang['user']['spamfilter_table_remove'];?></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
foreach($get_policy_list['whitelist'] as $wl):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$wl['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<input type="hidden" name="delete_prefid" value="<?=$wl['prefid'];?>">
|
||||
<?php
|
||||
if (filter_var($wl['object'], FILTER_VALIDATE_EMAIL)):
|
||||
?>
|
||||
<input type="hidden" name="delete_policy_list_item">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
<hr style="margin:5px 0px 7px 0px">
|
||||
<div class="row">
|
||||
@ -269,7 +292,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<input type="hidden" name="object_list" value="wl">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button type="submit" id="trigger_set_policy_list" name="trigger_set_policy_list" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
<button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -282,48 +305,38 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
|
||||
</div>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND `object`= :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
}
|
||||
if (count($rows) == 0):
|
||||
if (empty($get_policy_list['blacklist'])):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
while ($blacklistRow = array_shift($rows)):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$blacklistRow['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<input type="hidden" name="prefid" value="<?=$blacklistRow['prefid'];?>">
|
||||
<?php
|
||||
if ($blacklistRow['username'] != array_pop(explode('@', $username))):
|
||||
?>
|
||||
<input type="hidden" name="trigger_set_policy_list">
|
||||
<a href="#n" onclick="$(this).closest('form').submit()"><?=$lang['user']['spamfilter_table_remove'];?></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
endwhile;
|
||||
else:
|
||||
foreach($get_policy_list['blacklist'] as $bl):
|
||||
?>
|
||||
<div class="row striped">
|
||||
<form class="form-inline" method="post">
|
||||
<div class="col-xs-6"><code><?=$bl['value'];?></code></div>
|
||||
<div class="col-xs-6">
|
||||
<?php
|
||||
if (filter_var($bl['object'], FILTER_VALIDATE_EMAIL)):
|
||||
?>
|
||||
<input type="hidden" name="delete_prefid" value="<?=$bl['prefid'];?>">
|
||||
<input type="hidden" name="delete_policy_list_item">
|
||||
<a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
<hr style="margin:5px 0px 7px 0px">
|
||||
<div class="row">
|
||||
@ -333,7 +346,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
<input type="hidden" name="object_list" value="bl">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button type="submit" id="trigger_set_policy_list" name="trigger_set_policy_list" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
<button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -359,19 +372,144 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" id="trigger_set_tls_policy" name="trigger_set_tls_policy" class="btn btn-default"><?=$lang['user']['save_changes'];?></button>
|
||||
<button type="submit" id="edit_tls_policy" name="edit_tls_policy" class="btn btn-default"><?=$lang['user']['save_changes'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="Syncjobs">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable id="timelimitedaliases">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort-table" style="min-width: 96px;">Server:Port</th>
|
||||
<th class="sort-table" style="min-width: 96px;"><?=$lang['user']['encryption'];?></th>
|
||||
<th class="sort-table" style="min-width: 96px;"><?=$lang['user']['username'];?></th>
|
||||
<th class="sort-table" style="min-width: 96px;"><?=$lang['user']['excludes'];?></th>
|
||||
<th class="sort-table" style="min-width: 35px;"><?=$lang['user']['interval'];?></th>
|
||||
<th class="sort-table" style="min-width: 35px;"><?=$lang['user']['last_run'];?></th>
|
||||
<th class="sort-table" style="min-width: 35px;">Log</th>
|
||||
<th class="sort-table" style="max-width: 35px;"><?=$lang['user']['active'];?></th>
|
||||
<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['user']['action'];?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$get_syncjobs = get_syncjobs($username);
|
||||
if (!empty($get_syncjobs)):
|
||||
foreach ($get_syncjobs as $row):
|
||||
?>
|
||||
<tr id="data">
|
||||
<td><?=htmlspecialchars($row['host1'] . ':' . $row['port1']);?></td>
|
||||
<td><?=htmlspecialchars($row['enc1']);?></td>
|
||||
<td><?=htmlspecialchars($row['user1']);?></td>
|
||||
<td><?=($row['exclude'] == '') ? '✘' : '<code>' . $row['exclude'] . '</code>';?></td>
|
||||
<td><?=htmlspecialchars($row['mins_interval']);?> min</td>
|
||||
<td><?=(empty($row['last_run'])) ? '✘' : htmlspecialchars(date($lang['user']['syncjob_full_date'], strtotime($row['last_run'] . ' UTC')));?></td>
|
||||
<td>
|
||||
<?php
|
||||
if (empty($row['returned_text'])) {
|
||||
echo '✘';
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<a href="#logModal" data-toggle="modal" data-log-text="<?=htmlspecialchars($row['returned_text']);?>">Open logs</a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?=($row['active'] == '1') ? '✔' : '✘';?></td>
|
||||
<td style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<a href="/edit.php?syncjob=<?=urlencode($row['id']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['user']['edit'];?></a>
|
||||
<a href="/delete.php?syncjob=<?=urlencode($row['id']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['user']['remove'];?></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;
|
||||
else:
|
||||
?>
|
||||
<tr id="no-data"><td colspan="9" style="text-align: center; font-style: italic;"><?=$lang['user']['no_record'];?></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr id="no-data">
|
||||
<td colspan="9" style="text-align: center; font-style: normal; border-top: 1px solid #e7e7e7;">
|
||||
<a href="/add.php?syncjob"><?=$lang['user']['create_syncjob'];?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
|
||||
/*
|
||||
/ USER OR DOMAIN ADMIN
|
||||
*/
|
||||
|
||||
?>
|
||||
<div class="modal fade" id="logModal" tabindex="-1" role="dialog" aria-labelledby="logTextLabel">
|
||||
<div class="modal-dialog" style="width:90%" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<span id="logText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:200px;"></div>
|
||||
<div class="modal fade" id="pwChangeModal" tabindex="-1" role="dialog" aria-labelledby="pwChangeModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" role="form" method="post" autocomplete="off">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_new_pass"><?=$lang['user']['new_password'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" name="user_new_pass" id="user_new_pass" autocomplete="off" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_new_pass2"><?=$lang['user']['new_password_repeat'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" name="user_new_pass2" id="user_new_pass2" autocomplete="off" required>
|
||||
<p class="help-block"><?=$lang['user']['new_password_description'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="user_old_pass"><?=$lang['user']['password_now'];?></label>
|
||||
<div class="col-sm-5">
|
||||
<input type="password" class="form-control" name="user_old_pass" id="user_old_pass" autocomplete="off" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<button type="submit" name="edit_<?=($_SESSION['mailcow_cc_role'] == "domainadmin") ? "domain_admin" : "user_account";?>" class="btn btn-sm btn-success"><?=$lang['user']['change_password'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</div> <!-- /container -->
|
||||
<script src="js/sorttable.js"></script>
|
||||
<script src="js/user.js"></script>
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
header('Location: /');
|
||||
exit();
|
||||
}
|
||||
|
@ -135,9 +135,8 @@ services:
|
||||
volumes:
|
||||
- ./data/conf/dovecot:/etc/dovecot
|
||||
- ./data/assets/ssl:/etc/ssl/mail/:ro
|
||||
- ./data/conf/sogo/:/etc/sogo/
|
||||
- vmail-vol-1:/var/vmail
|
||||
volumes_from:
|
||||
- sogo-mailcow
|
||||
environment:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
@ -203,18 +202,19 @@ services:
|
||||
- php-fpm-mailcow
|
||||
- rspamd-mailcow
|
||||
image: nginx:mainline
|
||||
volumes_from:
|
||||
- sogo-mailcow
|
||||
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/listen.template > /etc/nginx/conf.d/listen.active && nginx -g 'daemon off;'"
|
||||
environment:
|
||||
- HTTPS_PORT=${HTTPS_PORT}
|
||||
volumes:
|
||||
- ./data/web:/web:ro
|
||||
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
|
||||
- ./data/assets/ssl/:/etc/ssl/mail/:ro
|
||||
- ./data/conf/nginx/:/etc/nginx/conf.d/:ro
|
||||
- ./data/conf/nginx/:/etc/nginx/conf.d/:rw
|
||||
dns:
|
||||
- 172.22.1.254
|
||||
dns_search: mailcow-network
|
||||
ports:
|
||||
- "443:443"
|
||||
- "${HTTPS_PORT}:${HTTPS_PORT}"
|
||||
restart: always
|
||||
networks:
|
||||
mailcow-network:
|
||||
@ -228,7 +228,6 @@ networks:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 172.22.1.0/24
|
||||
gateway: 172.22.1.1
|
||||
|
||||
volumes:
|
||||
vmail-vol-1:
|
||||
|
@ -44,6 +44,7 @@ DBROOT=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
||||
# ------------------------------
|
||||
# You should leave that alone
|
||||
# Can also be 11.22.33.44:25 or 0.0.0.0:465 etc. for specific bindings
|
||||
HTTPS_PORT=443
|
||||
SMTP_PORT=25
|
||||
SMTPS_PORT=465
|
||||
SUBMISSION_PORT=587
|
||||
|
Loading…
Reference in New Issue
Block a user