mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2024-11-21 17:16:54 +02:00
Docs
This commit is contained in:
parent
5f7fb2e7c2
commit
d891bc8894
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
rebuild-images.sh
|
||||
data/conf/sogo/sieve.creds
|
||||
data/conf/dovecot/dovecot-master.passwd
|
||||
mailcow.conf
|
||||
mailcow.conf_backup
|
||||
data/conf/nginx/listen*active
|
||||
data/web/inc/vars.local.inc.php
|
||||
site/
|
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# mailcow: dockerized - 🐮 + 🐋 = 💕
|
||||
|
||||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JWBSYHF4SMC68)
|
||||
|
||||
Please see the official documentation for instructions => [mailcow.email/dockerized](https://mailcow.email/dockerized)
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
This is the GitHub theme for highlight.js
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
color: #333;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-javadoc {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.hljs-dartdoc,
|
||||
.tex .hljs-formula {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-list .hljs-keyword,
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rule .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body,
|
||||
.hljs-name {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.clojure .hljs-keyword,
|
||||
.scheme .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
background: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
color: #aaa;
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Sphinx doesn't have support for section dividers like we do in
|
||||
* MkDocs, this styles the section titles in the nav
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/175
|
||||
*/
|
||||
.wy-menu-vertical span {
|
||||
line-height: 18px;
|
||||
padding: 0.4045em 1.618em;
|
||||
display: block;
|
||||
position: relative;
|
||||
font-size: 90%;
|
||||
color: #838383;
|
||||
}
|
||||
|
||||
.wy-menu-vertical .subnav a {
|
||||
padding: 0.4045em 2.427em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Long navigations run off the bottom of the screen as the nav
|
||||
* area doesn't scroll.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/pull/202
|
||||
*/
|
||||
.wy-nav-side {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* readthedocs theme hides nav items when the window height is
|
||||
* too small to contain them.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/#348
|
||||
*/
|
||||
.wy-menu-vertical ul {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrap inline code samples otherwise they shoot of the side and
|
||||
* can't be read at all.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/313
|
||||
* https://github.com/mkdocs/mkdocs/issues/233
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
*/
|
||||
code {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make code blocks display as blocks and give them the appropriate
|
||||
* font size and padding.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/855
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
* https://github.com/mkdocs/mkdocs/issues/233
|
||||
*/
|
||||
pre code {
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
display: block;
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix link colors when the link text is inline code.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/718
|
||||
*/
|
||||
a code {
|
||||
color: #2980B9;
|
||||
}
|
||||
a:hover code {
|
||||
color: #3091d1;
|
||||
}
|
||||
a:visited code {
|
||||
color: #9B59B6;
|
||||
}
|
||||
|
||||
/*
|
||||
* The CSS classes from highlight.js seem to clash with the
|
||||
* ReadTheDocs theme causing some code to be incorrectly made
|
||||
* bold and italic.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/411
|
||||
*/
|
||||
pre .cs, pre .c {
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix some issues with the theme and non-highlighted code
|
||||
* samples. Without and highlighting styles attached the
|
||||
* formatting is broken.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/319
|
||||
*/
|
||||
.no-highlight {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Additions specific to the search functionality provided by MkDocs
|
||||
*/
|
||||
|
||||
.search-results article {
|
||||
margin-top: 23px;
|
||||
border-top: 1px solid #E1E4E5;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.search-results article:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
form .search-query {
|
||||
width: 100%;
|
||||
border-radius: 50px;
|
||||
padding: 6px 12px; /* csslint allow: box-model */
|
||||
border-color: #D1D4D5;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li ul {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li ul.subnav ul.subnav{
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.wy-menu-vertical .subnav li.current > a {
|
||||
padding-left: 2.42em;
|
||||
}
|
||||
.wy-menu-vertical .subnav li.current > ul li a {
|
||||
padding-left: 3.23em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improve inline code blocks within admonitions.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/656
|
||||
*/
|
||||
.admonition code {
|
||||
color: #404040;
|
||||
border: 1px solid #c7c9cb;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background: #f8fbfd;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Account for wide tables which go off the side.
|
||||
* Override borders to avoid wierdness on narrow tables.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
* https://github.com/mkdocs/mkdocs/pull/1034
|
||||
*/
|
||||
.rst-content .section .docutils {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
display: block;
|
||||
border: none;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #e1e4e5 !important; /* csslint allow: important */
|
||||
border-collapse: collapse;
|
||||
}
|
87
data/Dockerfiles/dovecot/Dockerfile
Normal file
87
data/Dockerfiles/dovecot/Dockerfile
Normal file
@ -0,0 +1,87 @@
|
||||
From ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@servercow.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install dovecot-common \
|
||||
dovecot-core \
|
||||
dovecot-imapd \
|
||||
dovecot-lmtpd \
|
||||
dovecot-managesieved \
|
||||
dovecot-sieve \
|
||||
dovecot-mysql \
|
||||
dovecot-pop3d \
|
||||
dovecot-dev \
|
||||
syslog-ng \
|
||||
syslog-ng-core \
|
||||
ca-certificates \
|
||||
supervisor \
|
||||
wget \
|
||||
curl \
|
||||
build-essential \
|
||||
autotools-dev \
|
||||
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 \
|
||||
&& ./configure --prefix=/usr \
|
||||
&& 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
|
||||
|
||||
EXPOSE 24 10001
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
28
data/Dockerfiles/dovecot/docker-entrypoint.sh
Executable file
28
data/Dockerfiles/dovecot/docker-entrypoint.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 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
|
||||
|
||||
# Do not do this every start-up, it may take a very long time. So we use a stat check here.
|
||||
if [[ $(stat -c %U /var/vmail/) != "vmail" ]] ; then chown -R vmail:vmail /var/vmail ; fi
|
||||
|
||||
# Create random master for SOGo sieve features
|
||||
RAND_USER=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1)
|
||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 24 | head -n 1)
|
||||
echo ${RAND_USER}:$(doveadm pw -s SHA1 -p ${RAND_PASS}) > /etc/dovecot/dovecot-master.passwd
|
||||
echo ${RAND_USER}:${RAND_PASS} > /etc/sogo/sieve.creds
|
||||
|
||||
exec "$@"
|
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 "$@"
|
8
data/Dockerfiles/dovecot/rspamd-pipe
Executable file
8
data/Dockerfiles/dovecot/rspamd-pipe
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
if [[ ${2} == "learn_spam" ]]; then
|
||||
/usr/bin/curl --data-binary @- http://rspamd:11334/learnspam < /dev/stdin
|
||||
elif [[ ${2} == "learn_ham" ]]; then
|
||||
/usr/bin/curl --data-binary @- http://rspamd:11334/learnham < /dev/stdin
|
||||
fi
|
||||
# Always return 0 to satisfy Dovecot...
|
||||
exit 0
|
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
|
0
data/Dockerfiles/mysql/.empty
Normal file
0
data/Dockerfiles/mysql/.empty
Normal file
0
data/Dockerfiles/nginx/.empty
Normal file
0
data/Dockerfiles/nginx/.empty
Normal file
26
data/Dockerfiles/pdns/Dockerfile
Normal file
26
data/Dockerfiles/pdns/Dockerfile
Normal file
@ -0,0 +1,26 @@
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@debinux.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN echo 'deb http://repo.powerdns.com/ubuntu xenial-rec-40 main' > /etc/apt/sources.list.d/pdns.list
|
||||
|
||||
RUN echo 'Package: pdns-*\n\
|
||||
Pin: origin repo.powerdns.com\n\
|
||||
Pin-Priority: 600\n' > /etc/apt/preferences.d/pdns
|
||||
|
||||
RUN apt-key adv --fetch-keys http://repo.powerdns.com/FD380FBB-pub.asc \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --force-yes pdns-recursor
|
||||
|
||||
CMD ["/usr/sbin/pdns_recursor"]
|
||||
|
||||
EXPOSE 53/udp
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
18
data/Dockerfiles/php-fpm/Dockerfile
Normal file
18
data/Dockerfiles/php-fpm/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM php:7.1-fpm
|
||||
MAINTAINER Andre Peters <andre.peters@servercow.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y zlib1g-dev libicu-dev g++ libidn11-dev libxml2-dev
|
||||
|
||||
RUN docker-php-ext-configure intl
|
||||
RUN docker-php-ext-install intl pdo pdo_mysql xmlrpc
|
||||
RUN pear install channel://pear.php.net/Net_IDNA2-0.1.1 Auth_SASL Net_IMAP NET_SMTP Net_IDNA2 Mail_mime
|
||||
|
||||
COPY ./docker-entrypoint.sh /
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["php-fpm"]
|
7
data/Dockerfiles/php-fpm/docker-entrypoint.sh
Executable file
7
data/Dockerfiles/php-fpm/docker-entrypoint.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ ! -d "/data/dkim/txt" || ! -d "/data/dkim/keys" ]] ; then mkdir -p /data/dkim/{txt,keys} ; chown -R www-data:www-data /data/dkim; fi
|
||||
if [[ $(stat -c %U /data/dkim/) != "www-data" ]] ; then chown -R www-data:www-data /data/dkim ; fi
|
||||
|
||||
exec "$@"
|
33
data/Dockerfiles/postfix/Dockerfile
Normal file
33
data/Dockerfiles/postfix/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
||||
From ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@servercow.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y --no-install-recommends supervisor \
|
||||
postfix \
|
||||
sasl2-bin \
|
||||
libsasl2-modules \
|
||||
postfix \
|
||||
postfix-mysql \
|
||||
postfix-pcre \
|
||||
syslog-ng \
|
||||
syslog-ng-core \
|
||||
ca-certificates
|
||||
|
||||
RUN sed -i -E 's/^(\s*)system\(\);/\1unix-stream("\/dev\/log");/' /etc/syslog-ng/syslog-ng.conf
|
||||
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY postfix.sh /opt/postfix.sh
|
||||
|
||||
EXPOSE 588
|
||||
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
16
data/Dockerfiles/postfix/postfix.sh
Executable file
16
data/Dockerfiles/postfix/postfix.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
trap "postfix stop" EXIT
|
||||
|
||||
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/*
|
||||
|
||||
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
|
17
data/Dockerfiles/postfix/supervisord.conf
Normal file
17
data/Dockerfiles/postfix/supervisord.conf
Normal file
@ -0,0 +1,17 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:syslog-ng]
|
||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||
redirect_stderr=true
|
||||
autostart=true
|
||||
stdout_syslog=true
|
||||
|
||||
[program:postfix]
|
||||
command=/opt/postfix.sh
|
||||
autorestart=true
|
||||
|
||||
[program:postfix-maillog]
|
||||
command=/usr/bin/tail -f /var/log/mail.log
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
0
data/Dockerfiles/redis/.empty
Normal file
0
data/Dockerfiles/redis/.empty
Normal file
26
data/Dockerfiles/rmilter/Dockerfile
Normal file
26
data/Dockerfiles/rmilter/Dockerfile
Normal file
@ -0,0 +1,26 @@
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@servercow.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN apt-key adv --fetch-keys http://rspamd.com/apt-stable/gpg.key \
|
||||
&& echo "deb http://rspamd.com/apt-stable/ xenial main" > /etc/apt/sources.list.d/rspamd.list \
|
||||
&& apt-get update \
|
||||
&& apt-get --no-install-recommends -y --force-yes install rmilter cron syslog-ng syslog-ng-core supervisor
|
||||
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
RUN sed -i -E 's/^(\s*)system\(\);/\1unix-stream("\/dev\/log");/' /etc/syslog-ng/syslog-ng.conf
|
||||
RUN touch /var/log/mail.log && chmod 640 /var/log/mail.log && chown root:adm /var/log/mail.log
|
||||
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
18
data/Dockerfiles/rmilter/supervisord.conf
Normal file
18
data/Dockerfiles/rmilter/supervisord.conf
Normal file
@ -0,0 +1,18 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:syslog-ng]
|
||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||
redirect_stderr=true
|
||||
autostart=true
|
||||
stdout_syslog=true
|
||||
|
||||
[program:rmilter]
|
||||
command=/usr/sbin/rmilter -n -c /etc/rmilter.conf.d/rmilter.conf
|
||||
user=_rmilter
|
||||
autorestart=true
|
||||
|
||||
[program:rmilter-syslog]
|
||||
command=/usr/bin/tail -f /var/log/mail.log
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
27
data/Dockerfiles/rspamd/Dockerfile
Normal file
27
data/Dockerfiles/rspamd/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@debinux.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& ln -sf /bin/true /usr/bin/ischroot
|
||||
|
||||
RUN apt-key adv --fetch-keys http://rspamd.com/apt-stable/gpg.key \
|
||||
&& echo "deb http://rspamd.com/apt-stable/ xenial main" > /etc/apt/sources.list.d/rspamd.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install rspamd ca-certificates
|
||||
|
||||
RUN echo '.include $LOCAL_CONFDIR/local.d/rspamd.conf.local' > /etc/rspamd/rspamd.conf.local
|
||||
# "Hardcoded" - we need them
|
||||
RUN echo 'settings = "http://nginx:8081/settings.php";' > /etc/rspamd/modules.d/settings.conf
|
||||
|
||||
CMD ["/usr/bin/rspamd","-f", "-u", "_rspamd", "-g", "_rspamd"]
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
USER _rspamd
|
||||
|
||||
EXPOSE 11333 11334
|
51
data/Dockerfiles/sogo/Dockerfile
Normal file
51
data/Dockerfiles/sogo/Dockerfile
Normal file
@ -0,0 +1,51 @@
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Andre Peters <andre.peters@servercow.de>
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LC_ALL C
|
||||
ENV GOSU_VERSION 1.9
|
||||
|
||||
RUN dpkg-divert --local --rename --add /sbin/initctl \
|
||||
&& ln -sf /bin/true /sbin/initctl \
|
||||
&& dpkg-divert --local --rename --add /usr/bin/ischroot \
|
||||
&& 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 \
|
||||
&& 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" \
|
||||
&& export GNUPGHOME="$(mktemp -d)" \
|
||||
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
|
||||
&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
|
||||
&& rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
|
||||
&& chmod +x /usr/local/bin/gosu \
|
||||
&& gosu nobody true
|
||||
|
||||
RUN apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4 \
|
||||
&& echo "deb http://packages.inverse.ca/SOGo/nightly/3/ubuntu/ xenial xenial" > /etc/apt/sources.list.d/sogo.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y --force-yes install sogo sogo-activesync
|
||||
|
||||
RUN sed -i -E 's/^(\s*)system\(\);/\1unix-stream("\/dev\/log");/' /etc/syslog-ng/syslog-ng.conf
|
||||
RUN echo '* * * * * sogo /usr/sbin/sogo-ealarms-notify' > /etc/cron.d/sogo
|
||||
RUN echo '* * * * * sogo /usr/sbin/sogo-tool expire-sessions 60' >> /etc/cron.d/sogo
|
||||
RUN echo '0 0 * * * sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds' >> /etc/cron.d/sogo
|
||||
|
||||
COPY ./reconf-domains.sh /
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
|
||||
#EXPOSE 20000
|
||||
#EXPOSE 9191
|
||||
#EXPOSE 9192
|
||||
|
||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
98
data/Dockerfiles/sogo/reconf-domains.sh
Executable file
98
data/Dockerfiles/sogo/reconf-domains.sh
Executable file
@ -0,0 +1,98 @@
|
||||
#!/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, 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, ''), 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_domain_alias_address gda ON gda.username = mailbox.username
|
||||
WHERE mailbox.active = '1';
|
||||
EOF
|
||||
|
||||
|
||||
mkdir -p /var/lib/sogo/GNUstep/Defaults/
|
||||
|
||||
# Generate plist header with timezone data
|
||||
cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//GNUstep//DTD plist 0.9//EN" "http://www.gnustep.org/plist-0_9.xml">
|
||||
<plist version="0.9">
|
||||
<dict>
|
||||
<key>OCSAclURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_acl</string>
|
||||
<key>OCSCacheFolderURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_cache_folder</string>
|
||||
<key>OCSEMailAlarmsFolderURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_alarms_folder</string>
|
||||
<key>DomainFieldName</key>
|
||||
<string>domain</string>
|
||||
<key>OCSFolderInfoURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_folder_info</string>
|
||||
<key>OCSSessionsFolderURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_sessions_folder</string>
|
||||
<key>OCSStoreURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_store</string>
|
||||
<key>SOGoProfileURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_user_profile</string>
|
||||
<key>SOGoTimeZone</key>
|
||||
<string>${TZ}</string>
|
||||
<key>domains</key>
|
||||
<dict>
|
||||
EOF
|
||||
|
||||
# Generate multi-domain setup
|
||||
while read line
|
||||
do
|
||||
echo " <key>${line}</key>
|
||||
<dict>
|
||||
<key>SOGoMailDomain</key>
|
||||
<string>${line}</string>
|
||||
<key>SOGoUserSources</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>MailFieldNames</key>
|
||||
<array>
|
||||
<string>aliases</string>
|
||||
<string>ad_aliases</string>
|
||||
</array>
|
||||
<key>KindFieldName</key>
|
||||
<string>kind</string>
|
||||
<key>MultipleBookingsFieldName</key>
|
||||
<string>multiple_bookings</string>
|
||||
<key>canAuthenticate</key>
|
||||
<string>YES</string>
|
||||
<key>displayName</key>
|
||||
<string>GAL</string>
|
||||
<key>id</key>
|
||||
<string>${line}</string>
|
||||
<key>isAddressBook</key>
|
||||
<string>YES</string>
|
||||
<key>type</key>
|
||||
<string>sql</string>
|
||||
<key>userPasswordAlgorithm</key>
|
||||
<string>ssha256</string>
|
||||
<key>viewURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_view</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>" >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
done < <(mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain;" -B -N)
|
||||
|
||||
# Generate footer
|
||||
echo ' </dict>
|
||||
</dict>
|
||||
</plist>' >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
|
||||
# Fix permissions
|
||||
chown sogo:sogo -R /var/lib/sogo/
|
||||
chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
|
||||
sleep 99999
|
||||
|
||||
done
|
46
data/Dockerfiles/sogo/supervisord.conf
Normal file
46
data/Dockerfiles/sogo/supervisord.conf
Normal file
@ -0,0 +1,46 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:syslog-ng]
|
||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||
redirect_stderr=true
|
||||
autostart=true
|
||||
stdout_syslog=true
|
||||
|
||||
[group:sogo-group]
|
||||
programs=reconf-domains,sogo
|
||||
|
||||
[program:sogo]
|
||||
command=/usr/sbin/sogod
|
||||
user=sogo
|
||||
autorestart=true
|
||||
priority=20
|
||||
|
||||
[program:reconf-domains]
|
||||
command=/reconf-domains.sh
|
||||
autorestart=true
|
||||
priority=10
|
||||
|
||||
[program:sogo-syslog]
|
||||
command=/usr/bin/tail -f /var/log/syslog -f /var/log/sogo/sogo.log
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:cron]
|
||||
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
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=http://localhost:9191
|
4
data/assets/passwd/generate_passwords.sh
Executable file
4
data/assets/passwd/generate_passwords.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo DBPASS=$(openssl rand -base64 32 | tr -dc _A-Z-a-z-0-9)
|
||||
echo DBROOT=$(openssl rand -base64 32 | tr -dc _A-Z-a-z-0-9)
|
27
data/assets/ssl/ca-key.pem
Normal file
27
data/assets/ssl/ca-key.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAr+geb+b9p5PgNMDUwtK3NxtmUJrHvnCSxkkLEBPFp/vVvEQV
|
||||
eJQN3WNQVXjkqaAXQzWSkTz/URiKAKMSL/nx1+Es6HRXdR79GMc6kY1GBFMfhSwt
|
||||
BzblNZ++WpD4JB3bL5prMrf2HiTqe617dlENoqK0kBEDGZq3En07aV+MIRuT8HSW
|
||||
B4j1/St2DAKJYGCGVqPDgpFt7+aR8aXGkvoCMKpgiB32tNkmdDfzOdWmAdFS1KaV
|
||||
RK+ap9WmwNdMH0BzCud9vhuJjdUZlhfmWuuT5XaGU+fftIlI191XYOEZHe44TLy1
|
||||
xWwXUhc+BmhhSj3k75lNvtAxydVrZIyoVxpLHwIDAQABAoIBAARMxkGyAc1Q3hAs
|
||||
Dodco0Hjl5Ks1ekf01apfm28Lf63NzhM6cFyzQv2W4ZbWCuVUDxCWPzX4t3Wnbj6
|
||||
Q32MvI6sYG6mOWURhtpONG5OZ8G/Tmvw8oDUpLG03/BSzt4DJNJ7EdfBi3CdMmYn
|
||||
jXcM8Cpjk8pZwBumHoeDLCqdPU2p1onq+iwMdQDKfq1ESBwEuXIO82x9y/O6zxNZ
|
||||
HlWFDS5hLEt0UVWIV5aGK0/M/kzOCKwy7MMbJhHPYKy7Yvno2t+fJ6jiwswyEsCz
|
||||
M2Z3DUWzgrT4DdWSV2Bns0X/xID5kH7EXm7GqsudbHHJNnr7LWuowFSOzAX47t+N
|
||||
JgrRIaECgYEA1iFfpgO/awiNQLV1VpgA3pqzmFddEh74sFqILkSGd2fxH6BbgXJB
|
||||
z+7Cu6jij8Odvf48suKsG9K0OwAehnR/ZgkrQmnKftf/pEZ+iLdsS/T8IZAXjQ4g
|
||||
cLlYOOMuqIi8Ev1nT0/++IaSKro0CSDuuNtkqRCQ/ZMJtWzFxw3yZRcCgYEA0k1m
|
||||
vaxvkSXqrYvFjDkPM5gUXcE4wx9t6Y4iwmRISLe6bJcfVfaT9oCz4o6p4dxZsoXw
|
||||
SFSazFedqwQlzXMrrBd2rHYgg13N9LU9TggZXtSMOdye+dxk24P7GmJdWH5+S5vm
|
||||
TqATs105AD95p7X8+H1TpW4liwW+eNjFqqO8HzkCgYBIuVj01z0BqwveOEK7wDA7
|
||||
aisoyDMR3nbz3it2G0vX7fNUnG+3jQiRCDQW7ArWbMd8KYaP8rAlWvBfQXEclSBX
|
||||
lTGeArQFVHK8Zjy/Thx3x6KB+6AkBfI6lphB6daE4ruNb4bQxwh/e6TU4hyeJRMu
|
||||
sUSErt2vYWrgtSqOqkvyzQKBgBKExFZRd+WVLCwqEbQ+VgtaCfkTibcM7nXRkVgC
|
||||
0qasnxru19CPDQp43N5HZ8g+yhtBVh5YbOUvle+4Rsfnq2HVExsur8BBo2A4EXTs
|
||||
m6dRGiQCPHGOKcd2wMbbAJNJWD+6M7aavAFgZSOTc1gEW4laJ+J6Z43tbI9hr05O
|
||||
asNpAoGAFje1QFMYw8s8ZTYVrfwafgDB/BNnQRVnQwTZRXcabAT5O0Wc8hTDPOun
|
||||
aBNJ3oKSwBvt7Snsn1G/oeH0aZ6cI8kkYE+dyQ5YqSZZUbJF6g771iNv4lMvxRBN
|
||||
BT/ihKzXb/t47z6W8dL5N1BSZ0KrwIrEkqCeHBlAW+G/FArrbZU=
|
||||
-----END RSA PRIVATE KEY-----
|
18
data/assets/ssl/ca.pem
Normal file
18
data/assets/ssl/ca.pem
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICzjCCAbigAwIBAgIRALtgn1eSIUIhoGv9nq94NYEwCwYJKoZIhvcNAQELMBIx
|
||||
EDAOBgNVBAoTB21haWxjb3cwHhcNMTYxMjEzMTAxMTAwWhcNMTkxMTI4MTAxMTAw
|
||||
WjASMRAwDgYDVQQKEwdtYWlsY293MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAr+geb+b9p5PgNMDUwtK3NxtmUJrHvnCSxkkLEBPFp/vVvEQVeJQN3WNQ
|
||||
VXjkqaAXQzWSkTz/URiKAKMSL/nx1+Es6HRXdR79GMc6kY1GBFMfhSwtBzblNZ++
|
||||
WpD4JB3bL5prMrf2HiTqe617dlENoqK0kBEDGZq3En07aV+MIRuT8HSWB4j1/St2
|
||||
DAKJYGCGVqPDgpFt7+aR8aXGkvoCMKpgiB32tNkmdDfzOdWmAdFS1KaVRK+ap9Wm
|
||||
wNdMH0BzCud9vhuJjdUZlhfmWuuT5XaGU+fftIlI191XYOEZHe44TLy1xWwXUhc+
|
||||
BmhhSj3k75lNvtAxydVrZIyoVxpLHwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAKww
|
||||
DwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQsDggEBAF36qnigBDvvqRI0xksc
|
||||
NkGFMB3JLKznOZ0DrWUx121/GHFaNNNeI7ECmyk2eRYKCEZNnxWa1/LJ7GWn7lRU
|
||||
JD3OeWbhBUgA+HXoKl/jzXokuXMjYi/eFrgOofk2AqNDA5ioduS6A4vL8UDQc+74
|
||||
WSS8za4zoVR4GtxqDG+msRzTNVWXRcaaaWSrWMfZtQcEKIeQGDkcccvZ+mzlFUsH
|
||||
G1xxKuOPGjAwrxda4x+FY/dYdPbRV8ua0RQmYUMnROv507QnGZ9FdzdrvisZ67xx
|
||||
5BfxbApAyxDD/p7B4Zh1daga2LYGRwMJuwYjXlw9uNxJVQwcxg4nppWF1KZ4Fz0c
|
||||
EjY=
|
||||
-----END CERTIFICATE-----
|
19
data/assets/ssl/cert.pem
Normal file
19
data/assets/ssl/cert.pem
Normal file
@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBDCCAe6gAwIBAgIQeJMoL/3dxhxhT9EwuRTL/DALBgkqhkiG9w0BAQswEjEQ
|
||||
MA4GA1UEChMHbWFpbGNvdzAeFw0xNjEyMTMxMDExMDBaFw0xOTExMjgxMDExMDBa
|
||||
MC0xEDAOBgNVBAoTB21haWxjb3cxGTAXBgNVBAMTEG1haWwuZXhhbXBsZS5vcmcw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRg0xT3At9DSb3H5OMp3K1
|
||||
MpXAgYyotSK6TS61fC0QEHy2fMXiws7Agcye6Ln7CG63Fe1eN2jkdlefy9xJivS8
|
||||
y5w0M8i168v5znzC8fnylL2iOiSYfK/B/oEqfU7YH4RcegO53oDDIUZmi4Frgnu7
|
||||
39VVOU1ZyHEVqGJ2H2aAIkoZRjGzumD9Ym4LWGidtKJzBgFt/qmhUeWXipM8w281
|
||||
XkQnJU79+x2ywnJSvEZ3r/ZVJC7kbjiVw+/k15k9Cxk6Ik8wmJ0X/+xWxoZomHQI
|
||||
1LM0VKAS/iaU95dn2bplvL6jTiiyWAbrMjSKs4XbPt/fIbOicNkj6+CFy0MVfyyH
|
||||
AgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIAqDAdBgNVHSUEFjAUBggrBgEFBQcDAgYI
|
||||
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQsDggEBAI/jBJa1P8nB
|
||||
eHUN5muQmjBVDVOYyWAAEapOe2HYsBcpjaB2H8Iw3DQzJtz6peYeYSCmHRVqFLCm
|
||||
VPrq36l9mPUotyPDPlQQAxCj9R2+WbGaJO+N/E1F8FQ94dr3jqwUyfjVPoqEjmIH
|
||||
NFkvbA0RJOeBm9oYGdhM0wjOBV9c9MTHFG82nQ/zQeTuPb7GXuKIOXYCxoLNOZMw
|
||||
UJ02Cqjv5ImrgOhcstAKX3Ip0urSvZUGvtPla4CGh+M6yDFJ08GzX6OiMIH207RW
|
||||
jAbUXXERSUv/7hysdDjGo5HZjCeMzVu9KAxoZXqnmvkk8g2swKWtWBRcoeU1VGx0
|
||||
Bx4Q4KMjuYQ=
|
||||
-----END CERTIFICATE-----
|
8
data/assets/ssl/dhparams.pem
Normal file
8
data/assets/ssl/dhparams.pem
Normal file
@ -0,0 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEA9iHB0CRDhV8wfBgqnmvuJpl0fzL3qL75R4ZvQHlfMNLrxuIz2x9D
|
||||
9zcDhPcBTVzV5Ay0AAkke4wP6r6wDQqXqBP4Y8IOkYAyLh3jM40jfHQzQt+5JdQl
|
||||
ond3kiscBsFOch/vMfSLMu3lAb0YhPNTvrxhMz7LcVAWYl82swASupdiKR+MgaQr
|
||||
XsugpmDKsHW60VmIM9B7K9Y+rNHwvMWkmISd0KxA8oOy1WJvsVEissMALZDE3c4w
|
||||
2xHmO2lXxgEx3aez28736t4m/KW3g9Zr31a1M0KusmfY//fGkPk4NUrLBOS2xrgp
|
||||
Y/rG1qSBdcVyerM0Ki93qCyHKYu4ene0OwIBAg==
|
||||
-----END DH PARAMETERS-----
|
27
data/assets/ssl/key.pem
Normal file
27
data/assets/ssl/key.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA0YNMU9wLfQ0m9x+TjKdytTKVwIGMqLUiuk0utXwtEBB8tnzF
|
||||
4sLOwIHMnui5+whutxXtXjdo5HZXn8vcSYr0vMucNDPItevL+c58wvH58pS9ojok
|
||||
mHyvwf6BKn1O2B+EXHoDud6AwyFGZouBa4J7u9/VVTlNWchxFahidh9mgCJKGUYx
|
||||
s7pg/WJuC1honbSicwYBbf6poVHll4qTPMNvNV5EJyVO/fsdssJyUrxGd6/2VSQu
|
||||
5G44lcPv5NeZPQsZOiJPMJidF//sVsaGaJh0CNSzNFSgEv4mlPeXZ9m6Zby+o04o
|
||||
slgG6zI0irOF2z7f3yGzonDZI+vghctDFX8shwIDAQABAoIBAQC9kiLnIgxXGyZt
|
||||
pmmYdA6re1jatZ2zLSp+DcY8ul3/0hs195IKCyCOOSQPiR520Pt0t+duP46uYZIJ
|
||||
aakp9gxaI5Vz+oMacH/AyaBDuDTj1Mf9WMSyIOfbDVCMRJOppGLcVh62+Gfjp2EO
|
||||
+h2hTJBuvypFkbK2kVIZOaHVpbXWKw1oYuEcTftk9XfxxvfSMw1HQ12/P2CAcbaa
|
||||
jPmVbisunv6kpXtewSBTcaLSYWJf1MYD5Hi8fzkD2FJSXYbfQd8RKvT2rj6FA7ux
|
||||
CDMzbYhdnd7lc63OARCIjfCRNtDT1cZ3gR1CQHD98lWxmPQIZukv+w7s/bSrFgnQ
|
||||
ROZ0ghBJAoGBAOmE/3d5FDmp0aJNxXynKcRGdpEEM4O40RIdqa2eR6Pa7aTRosao
|
||||
z0qVgdFuJrqjlB3jgedxXEX1M0abCUzzM9Q5F7JLl+KsjwRwpkIOkPiyUncLp7LK
|
||||
QbY3tvYBIdpjlF1USOMGRL4j11hqr4vQC/yPBF7jj81kCZDTbmZhp82jAoGBAOWu
|
||||
ql5QFUOlmqkuWIAFkiLEZhOu+ptqkE+zG50CCGMJIX0dJ2PHXFyNGInomAeT0nbI
|
||||
pbnK3x7KeEKiGrAqZFNCTHhApTwkrIj0L/RQbMDZ7u7j1AEUVNFEhIm62kg84FtG
|
||||
xtfxVxredE+NQc/tyV3hXegdNZxegALirlcMKIvNAoGAWFwIxk48Ru1o8z72QQqH
|
||||
lUsMRicOzwK5qV8r+xPvC6MlVL42F3F8rj4QFwzU/r4yp3SUjNyqC5aSRl8Xj9Re
|
||||
gijwPHi6Cf09SHLPliMo29GtvnnchJxfbPF7+23GP3p6gy4HPk/65u9s5nnH3uFk
|
||||
B7ad8sGsgg0eSXyXQ4okEn0CgYEAnogPuedGthlxBgMiPMMbmfm7hyyId4t3Ljuu
|
||||
/JExnsHnpobf8EPjoVIWNOIhRWGnrCtUEEhR9tvDZCKljyDDfKBPTdU496lMmX8K
|
||||
NnToi7gg7iy84T3aSVMktDgPgDrclMPmbZh8CeSvnVUfrtgu3Ci4+4Rlw5eKffNe
|
||||
aGDQ/6UCgYAbUq9mRT2WOXIo+Dchi9VzDWgtfOw5VEyqkSpb7hPiIYx5jNaENnVK
|
||||
cAi3iqbBgPJBuMlTrKmmaxdmssGOEZNJLuuXLDbCU+f5cpu5PQ4crC6UtRI5rlhp
|
||||
8Yc+oiv3HWbSw3sVRpMFB6NP4DnvgFW3B2Wdfb/lNzPCKWqBsX7gWw==
|
||||
-----END RSA PRIVATE KEY-----
|
247
data/conf/dovecot/dovecot.conf
Normal file
247
data/conf/dovecot/dovecot.conf
Normal file
@ -0,0 +1,247 @@
|
||||
auth_mechanisms = plain login
|
||||
#mail_debug = yes
|
||||
log_path = /var/log/mail.log
|
||||
disable_plaintext_auth = yes
|
||||
# Uncomment on NFS share
|
||||
#mmap_disable = yes
|
||||
#mail_fsync = always
|
||||
#mail_nfs_index = yes
|
||||
#mail_nfs_storage = yes
|
||||
login_log_format_elements = "user=<%u> method=%m rip=%r lip=%l mpid=%e %c %k"
|
||||
mail_home = /var/vmail/%d/%n
|
||||
mail_location = maildir:~/
|
||||
mail_plugins = quota acl zlib antispam
|
||||
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
|
||||
ssl_protocols = !SSLv3 !SSLv2
|
||||
ssl_prefer_server_ciphers = yes
|
||||
ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
|
||||
ssl_options = no_compression
|
||||
# Automatically regenerates every week
|
||||
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
|
||||
master = yes
|
||||
pass = yes
|
||||
}
|
||||
passdb {
|
||||
args = /etc/dovecot/sql/dovecot-mysql.conf
|
||||
driver = sql
|
||||
}
|
||||
namespace inbox {
|
||||
inbox = yes
|
||||
location =
|
||||
separator = /
|
||||
mailbox "Trash" {
|
||||
auto = subscribe
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Deleted Messages" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Deleted Items" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Gelöschte Objekte" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Papierkorb" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Itens Excluidos" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Itens Excluídos" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Lixeira" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Prullenbak" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Verwijderde items" {
|
||||
special_use = \Trash
|
||||
}
|
||||
mailbox "Archive" {
|
||||
auto = subscribe
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Archiv" {
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Archives" {
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Arquivo" {
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Arquivos" {
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Archief" {
|
||||
special_use = \Archive
|
||||
}
|
||||
mailbox "Sent" {
|
||||
auto = subscribe
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Sent Messages" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Sent Items" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Gesendet" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Gesendete Objekte" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Itens Enviados" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Enviados" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Verzonden items" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Verzonden" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Drafts" {
|
||||
auto = subscribe
|
||||
special_use = \Drafts
|
||||
}
|
||||
mailbox "Entwürfe" {
|
||||
special_use = \Drafts
|
||||
}
|
||||
mailbox "Rascunhos" {
|
||||
special_use = \Drafts
|
||||
}
|
||||
mailbox "Concepten" {
|
||||
special_use = \Drafts
|
||||
}
|
||||
mailbox "Junk" {
|
||||
auto = subscribe
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Junk E-mail" {
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Spam" {
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Lixo Eletrônico" {
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox "Ongewenste e-mail" {
|
||||
special_use = \Junk
|
||||
}
|
||||
prefix =
|
||||
}
|
||||
namespace {
|
||||
type = shared
|
||||
separator = /
|
||||
prefix = Shared/%%u/
|
||||
location = maildir:%%h/:INDEXPVT=~/Shared/%%u
|
||||
subscriptions = no
|
||||
list = yes
|
||||
}
|
||||
protocols = imap sieve lmtp pop3
|
||||
service dict {
|
||||
unix_listener dict {
|
||||
mode = 0660
|
||||
user = vmail
|
||||
group = vmail
|
||||
}
|
||||
}
|
||||
service auth {
|
||||
inet_listener auth-inet {
|
||||
port = 10001
|
||||
}
|
||||
unix_listener auth-master {
|
||||
mode = 0600
|
||||
user = vmail
|
||||
}
|
||||
unix_listener auth-userdb {
|
||||
mode = 0600
|
||||
user = vmail
|
||||
}
|
||||
user = root
|
||||
}
|
||||
service managesieve-login {
|
||||
inet_listener sieve {
|
||||
port = 4190
|
||||
}
|
||||
service_count = 1
|
||||
process_min_avail = 2
|
||||
vsz_limit = 128M
|
||||
}
|
||||
service imap {
|
||||
executable = imap imap-postlogin
|
||||
}
|
||||
service managesieve {
|
||||
process_limit = 256
|
||||
}
|
||||
service lmtp {
|
||||
inet_listener lmtp-inet {
|
||||
port = 24
|
||||
}
|
||||
user = vmail
|
||||
}
|
||||
listen = *,[::]
|
||||
ssl_cert = </etc/ssl/mail/cert.pem
|
||||
ssl_key = </etc/ssl/mail/key.pem
|
||||
userdb {
|
||||
args = /etc/dovecot/sql/dovecot-mysql.conf
|
||||
driver = sql
|
||||
}
|
||||
protocol imap {
|
||||
mail_plugins = quota imap_quota imap_acl acl zlib imap_zlib antispam
|
||||
}
|
||||
protocol lmtp {
|
||||
mail_plugins = quota sieve acl zlib
|
||||
auth_socket_path = /var/run/dovecot/auth-master
|
||||
}
|
||||
protocol sieve {
|
||||
managesieve_logout_format = bytes=%i/%o
|
||||
}
|
||||
plugin {
|
||||
acl_anyone = allow
|
||||
acl_shared_dict = file:/var/vmail/shared-mailboxes.db
|
||||
acl = vfile
|
||||
quota = dict:Userquota::proxy::sqlquota
|
||||
quota_rule2 = Trash:storage=+100%%
|
||||
antispam_backend = mailtrain
|
||||
antispam_spam = Junk
|
||||
antispam_trash = Trash
|
||||
antispam_mail_sendmail = /usr/local/bin/rspamd-pipe
|
||||
antispam_mail_spam = learn_spam
|
||||
antispam_mail_notspam = learn_ham
|
||||
# Do not complain about empty parameter
|
||||
antispam_mail_sendmail_args = --blind
|
||||
sieve = /var/vmail/sieve/%u.sieve
|
||||
sieve_after = /var/vmail/sieve/global.sieve
|
||||
sieve_max_script_size = 1M
|
||||
sieve_quota_max_scripts = 0
|
||||
sieve_quota_max_storage = 0
|
||||
}
|
||||
dict {
|
||||
sqlquota = mysql:/etc/dovecot/sql/dovecot-dict-sql.conf
|
||||
}
|
||||
remote 127.0.0.1 {
|
||||
disable_plaintext_auth = no
|
||||
}
|
||||
submission_host = postfix:588
|
||||
mail_max_userip_connections = 500
|
||||
service imap-postlogin {
|
||||
executable = script-login /usr/local/bin/postlogin.sh
|
||||
unix_listener imap-postlogin {
|
||||
}
|
||||
}
|
24
data/conf/dovecot/sieve_after
Normal file
24
data/conf/dovecot/sieve_after
Normal file
@ -0,0 +1,24 @@
|
||||
require "fileinto";
|
||||
require "mailbox";
|
||||
require "variables";
|
||||
require "subaddress";
|
||||
require "envelope";
|
||||
|
||||
if header :contains "X-Spam-Flag" "YES" {
|
||||
fileinto "Junk";
|
||||
}
|
||||
|
||||
if allof (
|
||||
envelope :detail :matches "to" "*",
|
||||
header :contains "X-Moo-Tag" "YES",
|
||||
mailboxexists "INBOX/${s}"
|
||||
) {
|
||||
fileinto "INBOX/${s}";
|
||||
}
|
||||
elsif allof (
|
||||
envelope :detail :matches "to" "*",
|
||||
header :contains "X-Moo-Tag" "YES"
|
||||
) {
|
||||
set :lower "s" "${1}";
|
||||
fileinto :create "INBOX/${s}";
|
||||
}
|
15
data/conf/dovecot/sql/dovecot-dict-sql.conf
Normal file
15
data/conf/dovecot/sql/dovecot-dict-sql.conf
Normal file
@ -0,0 +1,15 @@
|
||||
connect = "host=mysql dbname=mailcow user=mailcow password=mysafepasswd"
|
||||
|
||||
map {
|
||||
pattern = priv/quota/storage
|
||||
table = quota2
|
||||
username_field = username
|
||||
value_field = bytes
|
||||
}
|
||||
map {
|
||||
pattern = priv/quota/messages
|
||||
table = quota2
|
||||
username_field = username
|
||||
value_field = messages
|
||||
}
|
||||
|
6
data/conf/dovecot/sql/dovecot-mysql.conf
Normal file
6
data/conf/dovecot/sql/dovecot-mysql.conf
Normal file
@ -0,0 +1,6 @@
|
||||
driver = mysql
|
||||
connect = "host=mysql dbname=mailcow user=mailcow password=mysafepasswd"
|
||||
default_pass_scheme = SSHA256
|
||||
password_query = SELECT password FROM mailbox WHERE username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1')
|
||||
user_query = SELECT CONCAT('maildir:/var/vmail/',maildir) AS mail, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
|
||||
iterate_query = SELECT username FROM mailbox WHERE active='1';
|
14
data/conf/mysql/my.cnf
Normal file
14
data/conf/mysql/my.cnf
Normal file
@ -0,0 +1,14 @@
|
||||
[mysqld]
|
||||
character-set-client-handshake = FALSE
|
||||
character-set-server = utf8mb4
|
||||
collation-server = utf8mb4_unicode_ci
|
||||
innodb_file_per_table = TRUE
|
||||
innodb_file_format = barracuda
|
||||
innodb_large_prefix = TRUE
|
||||
#sql_mode=IGNORE_SPACE,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
|
||||
|
||||
[client]
|
||||
default-character-set = utf8mb4
|
||||
|
||||
[mysql]
|
||||
default-character-set = utf8mb4
|
18
data/conf/nginx/dynmaps.conf
Normal file
18
data/conf/nginx/dynmaps.conf
Normal file
@ -0,0 +1,18 @@
|
||||
server {
|
||||
listen 8081;
|
||||
index index.php index.html;
|
||||
server_name _;
|
||||
error_log /var/log/nginx/error.log;
|
||||
access_log /var/log/nginx/access.log;
|
||||
root /dynmaps;
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass phpfpm:9000;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
}
|
1
data/conf/nginx/listen.template
Normal file
1
data/conf/nginx/listen.template
Normal file
@ -0,0 +1 @@
|
||||
listen ${HTTPS_PORT};
|
136
data/conf/nginx/site.conf
Normal file
136
data/conf/nginx/site.conf
Normal file
@ -0,0 +1,136 @@
|
||||
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
|
||||
server {
|
||||
include /etc/nginx/conf.d/listen.active;
|
||||
include /etc/nginx/mime.types;
|
||||
charset utf-8;
|
||||
override_charset on;
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA';
|
||||
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
||||
ssl_ecdh_curve secp384r1;
|
||||
index index.php index.html;
|
||||
server_name _ autodiscover.* autoconfig.*;
|
||||
error_log /var/log/nginx/error.log;
|
||||
access_log /var/log/nginx/access.log;
|
||||
root /web;
|
||||
|
||||
location = /principals/ {
|
||||
rewrite ^ https://$host/SOGo/dav;
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass phpfpm:9000;
|
||||
fastcgi_index index.php;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param PHP_VALUE "max_execution_time = 1200
|
||||
max_input_time = 1200
|
||||
memory_limit = 64M";
|
||||
fastcgi_read_timeout 1200;
|
||||
}
|
||||
|
||||
rewrite ^(/save.+)$ /rspamd$1 last;
|
||||
location /rspamd/ {
|
||||
proxy_pass http://172.22.1.253:11334/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
}
|
||||
|
||||
location ^~ /inc/init.sql {
|
||||
deny all;
|
||||
}
|
||||
|
||||
if ($host ~* autodiscover\.(.*)) {
|
||||
rewrite ^(.*) /autodiscover.php last;
|
||||
}
|
||||
|
||||
if ($host ~* autoconfig\.(.*)) {
|
||||
rewrite ^(.*) /autoconfig.php last;
|
||||
}
|
||||
|
||||
location ^~ /Microsoft-Server-ActiveSync {
|
||||
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
||||
proxy_connect_timeout 1000;
|
||||
proxy_next_upstream timeout error;
|
||||
proxy_send_timeout 1000;
|
||||
proxy_read_timeout 1000;
|
||||
proxy_buffer_size 8k;
|
||||
proxy_buffers 4 32k;
|
||||
proxy_temp_file_write_size 64k;
|
||||
proxy_busy_buffers_size 64k;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
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:$server_port;
|
||||
proxy_set_header x-webobjects-server-port $server_port;
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 100m;
|
||||
}
|
||||
|
||||
location ^~ /SOGo {
|
||||
proxy_pass http://172.22.1.252:20000;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
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:$server_port;
|
||||
proxy_set_header x-webobjects-server-port $server_port;
|
||||
#proxy_connect_timeout 90;
|
||||
#proxy_send_timeout 90;
|
||||
#proxy_read_timeout 90;
|
||||
#proxy_buffer_size 4k;
|
||||
#proxy_buffers 4 32k;
|
||||
#proxy_busy_buffers_size 64k;
|
||||
#proxy_temp_file_write_size 64k;
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 100m;
|
||||
break;
|
||||
}
|
||||
|
||||
location /SOGo.woa/WebServerResources/ {
|
||||
proxy_pass http://172.22.1.252: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/ {
|
||||
proxy_pass http://172.22.1.252: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)$ {
|
||||
proxy_pass http://172.22.1.252: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
data/conf/pdns/pdns_custom.lua
Normal file
1
data/conf/pdns/pdns_custom.lua
Normal file
@ -0,0 +1 @@
|
||||
addNTA("mailcow-network", "nta for local")
|
41
data/conf/pdns/recursor.conf
Normal file
41
data/conf/pdns/recursor.conf
Normal file
@ -0,0 +1,41 @@
|
||||
allow-from=127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8
|
||||
config-dir=/etc/powerdns
|
||||
daemon=no
|
||||
disable-syslog=yes
|
||||
dnssec=process
|
||||
dnssec-log-bogus=yes
|
||||
dont-query=10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32
|
||||
export-etc-hosts=off
|
||||
# forward-zones=
|
||||
forward-zones-recurse=mailcow-network.=127.0.0.11
|
||||
local-address=0.0.0.0
|
||||
local-port=53
|
||||
loglevel=6
|
||||
# lowercase-outgoing=no
|
||||
lua-config-file=/etc/powerdns/pdns_custom.lua
|
||||
# max-cache-entries=1000000
|
||||
# max-cache-ttl=86400
|
||||
# max-mthreads=2048
|
||||
# max-negative-ttl=3600
|
||||
# max-packetcache-entries=500000
|
||||
# max-qperq=50
|
||||
# max-tcp-clients=128
|
||||
# max-tcp-per-client=0
|
||||
# max-total-msec=7000
|
||||
# minimum-ttl-override=0
|
||||
# network-timeout=1500
|
||||
# packetcache-servfail-ttl=60
|
||||
# packetcache-ttl=3600
|
||||
quiet=yes
|
||||
# security-poll-suffix=secpoll.powerdns.com.
|
||||
# serve-rfc1918=yes
|
||||
# server-down-max-fails=64
|
||||
# server-down-throttle-time=60
|
||||
setgid=pdns
|
||||
setuid=pdns
|
||||
# spoof-nearmiss-max=20
|
||||
# stack-size=200000
|
||||
# threads=2
|
||||
# trace=off
|
||||
version-string=PowerDNS Recursor
|
||||
webserver=no
|
93
data/conf/postfix/main.cf
Normal file
93
data/conf/postfix/main.cf
Normal file
@ -0,0 +1,93 @@
|
||||
biff = no
|
||||
append_dot_mydomain = no
|
||||
smtpd_tls_cert_file = /etc/ssl/mail/cert.pem
|
||||
smtpd_tls_key_file = /etc/ssl/mail/key.pem
|
||||
smtpd_use_tls=yes
|
||||
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
||||
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
|
||||
alias_maps = hash:/etc/aliases
|
||||
alias_database = hash:/etc/aliases
|
||||
relayhost =
|
||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
|
||||
mailbox_size_limit = 0
|
||||
recipient_delimiter = +
|
||||
inet_interfaces = all
|
||||
inet_protocols = all
|
||||
bounce_queue_lifetime = 1d
|
||||
broken_sasl_auth_clients = yes
|
||||
disable_vrfy_command = yes
|
||||
maximal_backoff_time = 1800s
|
||||
maximal_queue_lifetime = 1d
|
||||
message_size_limit = 26214400
|
||||
milter_default_action = accept
|
||||
milter_protocol = 6
|
||||
minimal_backoff_time = 300s
|
||||
plaintext_reject_code = 550
|
||||
postscreen_access_list = permit_mynetworks, cidr:/opt/postfix/conf/postscreen_access.cidr
|
||||
postscreen_bare_newline_enable = no
|
||||
postscreen_blacklist_action = drop
|
||||
postscreen_cache_cleanup_interval = 24h
|
||||
postscreen_cache_map = proxy:btree:$data_directory/postscreen_cache
|
||||
postscreen_dnsbl_action = enforce
|
||||
postscreen_dnsbl_sites = b.barracudacentral.org=127.0.0.2*7 dnsbl.inps.de=127.0.0.2*7 bl.mailspike.net=127.0.0.2*5 bl.mailspike.net=127.0.0.[10;11;12]*4 dnsbl.sorbs.net=127.0.0.10*8 dnsbl.sorbs.net=127.0.0.5*6 dnsbl.sorbs.net=127.0.0.7*3 dnsbl.sorbs.net=127.0.0.8*2 dnsbl.sorbs.net=127.0.0.6*2 dnsbl.sorbs.net=127.0.0.9*2 zen.spamhaus.org=127.0.0.[10;11]*8 zen.spamhaus.org=127.0.0.[4..7]*6 zen.spamhaus.org=127.0.0.3*4 zen.spamhaus.org=127.0.0.2*3 hostkarma.junkemailfilter.com=127.0.0.2*3 hostkarma.junkemailfilter.com=127.0.0.4*1 hostkarma.junkemailfilter.com=127.0.1.2*1 wl.mailspike.net=127.0.0.[18;19;20]*-2 hostkarma.junkemailfilter.com=127.0.0.1*-2
|
||||
postscreen_dnsbl_threshold = 8
|
||||
postscreen_dnsbl_ttl = 5m
|
||||
postscreen_greet_action = enforce
|
||||
postscreen_greet_banner = $smtpd_banner
|
||||
postscreen_greet_ttl = 2d
|
||||
postscreen_greet_wait = 3s
|
||||
postscreen_non_smtp_command_enable = no
|
||||
postscreen_pipelining_enable = no
|
||||
proxy_read_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_out_policy.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf, $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $smtpd_sender_login_maps
|
||||
queue_run_delay = 300s
|
||||
relay_domains = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf
|
||||
relay_recipient_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
|
||||
sender_dependent_default_transport_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_out_policy.cf
|
||||
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
|
||||
smtp_tls_cert_file = /etc/ssl/mail/cert.pem
|
||||
smtp_tls_key_file = /etc/ssl/mail/key.pem
|
||||
smtp_tls_loglevel = 1
|
||||
smtp_dns_support_level = dnssec
|
||||
smtp_tls_security_level = dane
|
||||
smtpd_data_restrictions = reject_unauth_pipelining, permit
|
||||
smtpd_delay_reject = yes
|
||||
smtpd_error_sleep_time = 10s
|
||||
smtpd_hard_error_limit = ${stress?1}${stress:5}
|
||||
smtpd_helo_required = yes
|
||||
smtpd_proxy_timeout = 600s
|
||||
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, check_recipient_access proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf, reject_invalid_helo_hostname, reject_unknown_reverse_client_hostname, reject_unauth_destination
|
||||
smtpd_sasl_auth_enable = yes
|
||||
smtpd_sasl_authenticated_header = yes
|
||||
smtpd_sasl_path = inet:dovecot:10001
|
||||
smtpd_sasl_type = dovecot
|
||||
smtpd_sender_login_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
|
||||
smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch, permit_mynetworks, reject_sender_login_mismatch, permit_sasl_authenticated, reject_unlisted_sender, reject_unknown_sender_domain
|
||||
smtpd_soft_error_limit = 3
|
||||
smtpd_tls_auth_only = yes
|
||||
smtpd_tls_dh1024_param_file = /etc/ssl/mail/dhparams.pem
|
||||
smtpd_tls_eecdh_grade = strong
|
||||
smtpd_tls_exclude_ciphers = ECDHE-RSA-RC4-SHA, RC4, aNULL
|
||||
smtpd_tls_loglevel = 1
|
||||
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
|
||||
smtp_tls_protocols = !SSLv2, !SSLv3
|
||||
lmtp_tls_mandatory_protocols = !SSLv2, !SSLv3
|
||||
lmtp_tls_protocols = !SSLv2, !SSLv3
|
||||
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
|
||||
smtpd_tls_protocols = !SSLv2, !SSLv3
|
||||
smtpd_tls_mandatory_ciphers = high
|
||||
smtpd_tls_security_level = may
|
||||
tls_ssl_options = NO_COMPRESSION
|
||||
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
|
||||
virtual_alias_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
|
||||
virtual_gid_maps = static:5000
|
||||
virtual_mailbox_base = /var/vmail/
|
||||
virtual_mailbox_domains = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
|
||||
virtual_mailbox_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_mailbox_maps.cf
|
||||
virtual_minimum_uid = 104
|
||||
virtual_transport = lmtp:inet:dovecot:24
|
||||
virtual_uid_maps = static:5000
|
||||
smtpd_milters = inet:rmilter:9900
|
||||
non_smtpd_milters = inet:rmilter:9900
|
||||
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
|
||||
mydestination = localhost.localdomain, localhost
|
45
data/conf/postfix/master.cf
Normal file
45
data/conf/postfix/master.cf
Normal file
@ -0,0 +1,45 @@
|
||||
smtp inet n - n - 1 postscreen
|
||||
smtpd pass - - n - - smtpd
|
||||
-o smtpd_helo_restrictions=permit_mynetworks,reject_non_fqdn_helo_hostname
|
||||
smtps inet n - n - - smtpd
|
||||
-o smtpd_tls_wrappermode=yes
|
||||
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
|
||||
submission inet n - n - - smtpd
|
||||
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
|
||||
-o smtpd_enforce_tls=yes
|
||||
-o smtpd_tls_security_level=encrypt
|
||||
-o tls_preempt_cipherlist=yes
|
||||
588 inet n - n - - smtpd
|
||||
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
|
||||
-o smtpd_tls_auth_only=no
|
||||
smtp_enforced_tls unix - - n - - smtp
|
||||
-o smtp_tls_security_level=encrypt
|
||||
-o syslog_name=enforced-tls-smtp
|
||||
-o smtp_delivery_status_filter=pcre:/opt/postfix/conf/smtp_dsn_filter
|
||||
tlsproxy unix - - n - 0 tlsproxy
|
||||
dnsblog unix - - n - 0 dnsblog
|
||||
pickup fifo n - n 60 1 pickup
|
||||
cleanup unix n - n - 0 cleanup
|
||||
qmgr fifo n - n 300 1 qmgr
|
||||
tlsmgr unix - - n 1000? 1 tlsmgr
|
||||
rewrite unix - - n - - trivial-rewrite
|
||||
bounce unix - - n - 0 bounce
|
||||
defer unix - - n - 0 bounce
|
||||
trace unix - - n - 0 bounce
|
||||
verify unix - - n - 1 verify
|
||||
flush unix n - n 1000? 0 flush
|
||||
proxymap unix - - n - - proxymap
|
||||
proxywrite unix - - n - 1 proxymap
|
||||
smtp unix - - n - - smtp
|
||||
relay unix - - n - - smtp
|
||||
showq unix n - n - - showq
|
||||
error unix - - n - - error
|
||||
retry unix - - n - - error
|
||||
discard unix - - n - - discard
|
||||
local unix - n n - - local
|
||||
virtual unix - n n - - virtual
|
||||
lmtp unix - - n - - lmtp
|
||||
anvil unix - - n - 1 anvil
|
||||
scache unix - - n - 1 scache
|
||||
maildrop unix - n n - - pipe flags=DRhu
|
||||
user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
654
data/conf/postfix/postscreen_access.cidr
Normal file
654
data/conf/postfix/postscreen_access.cidr
Normal file
@ -0,0 +1,654 @@
|
||||
# Generated by Postwhite v1.30 on Thu Dec 8 21:11:27 CET 2016
|
||||
# https://github.com/stevejenkins/postwhite/
|
||||
# 651 total rules
|
||||
2a00:1450:4000::/36 permit
|
||||
2a01:111:f400::/48 permit
|
||||
2a04:35c0::/29 permit
|
||||
2c0f:fb50:4000::/36 permit
|
||||
5.135.24.0/24 permit
|
||||
8.20.114.31 permit
|
||||
8.25.194.0/23 permit
|
||||
8.25.196.0/23 permit
|
||||
12.130.86.238 permit
|
||||
13.111.0.0/19 permit
|
||||
17.36.0.0/16 permit
|
||||
17.41.0.0/16 permit
|
||||
17.110.0.0/15 permit
|
||||
17.120.0.0/16 permit
|
||||
17.133.0.0/16 permit
|
||||
17.139.0.0/16 permit
|
||||
17.142.0.0/15 permit
|
||||
17.151.1.0/24 permit
|
||||
17.158.0.0/15 permit
|
||||
17.162.0.0/15 permit
|
||||
17.164.0.0/16 permit
|
||||
17.171.37.0/24 permit
|
||||
17.172.0.0/16 permit
|
||||
23.21.83.90 permit
|
||||
23.23.237.213 permit
|
||||
23.96.52.53 permit
|
||||
23.100.122.175 permit
|
||||
23.103.128.0/19 permit
|
||||
23.103.131.7 permit
|
||||
23.103.191.0/24 permit
|
||||
23.103.198.0/23 permit
|
||||
23.103.200.0/21 permit
|
||||
23.103.208.0/21 permit
|
||||
23.103.224.0/19 permit
|
||||
23.253.182.0/24 permit
|
||||
23.253.182.103 permit
|
||||
23.253.183.0/24 permit
|
||||
23.253.183.145 permit
|
||||
23.253.183.146 permit
|
||||
23.253.183.147 permit
|
||||
23.253.183.148 permit
|
||||
23.253.183.150 permit
|
||||
27.126.146.0/24 permit
|
||||
37.59.69.128/25 permit
|
||||
37.59.249.0/24 permit
|
||||
37.188.97.188/32 permit
|
||||
40.92.0.0/14 permit
|
||||
40.96.32.50 permit
|
||||
40.97.113.34 permit
|
||||
40.97.113.210 permit
|
||||
40.97.153.146 permit
|
||||
40.97.155.26 permit
|
||||
40.97.156.114 permit
|
||||
40.97.160.2 permit
|
||||
40.97.164.146 permit
|
||||
40.97.166.138 permit
|
||||
40.97.170.154 permit
|
||||
40.107.0.0/17 permit
|
||||
40.107.128.0/18 permit
|
||||
41.74.192.0/22 permit
|
||||
41.74.196.0/22 permit
|
||||
41.74.200.0/22 permit
|
||||
41.74.201.0/24 permit
|
||||
41.74.204.0/22 permit
|
||||
41.74.205.0/24 permit
|
||||
46.19.168.0/23 permit
|
||||
50.18.45.249 permit
|
||||
50.18.121.236 permit
|
||||
50.18.121.248 permit
|
||||
50.18.123.221 permit
|
||||
50.18.124.70 permit
|
||||
50.18.125.97 permit
|
||||
50.18.125.237 permit
|
||||
50.18.126.162 permit
|
||||
50.22.164.201 permit
|
||||
50.23.218.192/27 permit
|
||||
50.31.32.0/19 permit
|
||||
50.31.36.197 permit
|
||||
50.31.36.199 permit
|
||||
50.31.36.205 permit
|
||||
50.31.36.208 permit
|
||||
50.31.36.213 permit
|
||||
50.31.60.1 permit
|
||||
50.31.156.96/27 permit
|
||||
50.207.218.237 permit
|
||||
51.4.71.62 permit
|
||||
52.0.20.102 permit
|
||||
52.95.48.152/29 permit
|
||||
52.95.49.88/29 permit
|
||||
52.205.61.79 permit
|
||||
54.172.97.247 permit
|
||||
54.173.229.38 permit
|
||||
54.214.39.184 permit
|
||||
54.240.0.0/18 permit
|
||||
54.241.16.209 permit
|
||||
54.243.205.80 permit
|
||||
54.244.242.0/24 permit
|
||||
62.17.146.128/26 permit
|
||||
63.80.14.0/23 permit
|
||||
63.111.28.137 permit
|
||||
63.128.21.0/24 permit
|
||||
64.4.22.64/26 permit
|
||||
64.18.0.0/20 permit
|
||||
64.20.241.45 permit
|
||||
64.34.47.128/27 permit
|
||||
64.34.57.192/26 permit
|
||||
64.79.155.0/24 permit
|
||||
64.79.155.192 permit
|
||||
64.127.115.252 permit
|
||||
64.132.88.0/23 permit
|
||||
64.132.92.0/24 permit
|
||||
64.135.77.0/24 permit
|
||||
64.135.83.0/24 permit
|
||||
64.233.160.0/19 permit
|
||||
65.39.215.0/24 permit
|
||||
65.54.51.64/26 permit
|
||||
65.54.61.64/26 permit
|
||||
65.54.121.120/29 permit
|
||||
65.54.121.124/31 permit
|
||||
65.54.190.0/24 permit
|
||||
65.54.241.0/24 permit
|
||||
65.55.33.64/28 permit
|
||||
65.55.34.0/24 permit
|
||||
65.55.42.224/28 permit
|
||||
65.55.52.224/27 permit
|
||||
65.55.77.28 permit
|
||||
65.55.78.128/25 permit
|
||||
65.55.81.48/28 permit
|
||||
65.55.81.54/31 permit
|
||||
65.55.85.12 permit
|
||||
65.55.88.0/24 permit
|
||||
65.55.90.0/24 permit
|
||||
65.55.94.0/25 permit
|
||||
65.55.111.0/24 permit
|
||||
65.55.113.64/26 permit
|
||||
65.55.116.0/25 permit
|
||||
65.55.126.0/25 permit
|
||||
65.55.169.0/24 permit
|
||||
65.55.174.0/25 permit
|
||||
65.55.178.128/27 permit
|
||||
65.55.234.192/26 permit
|
||||
65.110.161.77 permit
|
||||
65.212.180.36 permit
|
||||
65.242.92.0/24 permit
|
||||
65.242.92.15 permit
|
||||
66.77.16.201/32 permit
|
||||
66.102.0.0/20 permit
|
||||
66.135.215.0/24 permit
|
||||
66.135.222.1 permit
|
||||
66.211.168.230/31 permit
|
||||
66.211.184.0/23 permit
|
||||
66.220.144.128/25 permit
|
||||
66.220.155.0/24 permit
|
||||
66.220.155.128/25 permit
|
||||
66.220.157.0/25 permit
|
||||
66.231.80.0/20 permit
|
||||
66.249.80.0/20 permit
|
||||
67.23.31.6 permit
|
||||
67.72.99.26 permit
|
||||
67.221.168.65 permit
|
||||
67.228.2.24/30 permit
|
||||
67.228.21.184/29 permit
|
||||
67.228.37.4/30 permit
|
||||
67.228.50.32/27 permit
|
||||
67.228.50.54/31 permit
|
||||
67.231.145.42 permit
|
||||
67.231.153.30 permit
|
||||
68.232.192.0/20 permit
|
||||
69.63.178.128/25 permit
|
||||
69.63.179.25 permit
|
||||
69.63.184.0/25 permit
|
||||
69.65.42.195 permit
|
||||
69.65.49.192/29 permit
|
||||
69.162.98.0/24 permit
|
||||
69.171.232.0/24 permit
|
||||
69.171.232.128/25 permit
|
||||
69.171.244.0/24 permit
|
||||
70.37.151.128/25 permit
|
||||
70.42.149.35 permit
|
||||
72.3.185.0/24 permit
|
||||
72.3.237.64/28 permit
|
||||
72.5.230.111/32 permit
|
||||
72.14.192.0/18 permit
|
||||
72.21.192.0/19 permit
|
||||
72.21.212.0/25 permit
|
||||
72.21.217.142/32 permit
|
||||
72.32.154.0/24 permit
|
||||
72.32.217.0/24 permit
|
||||
72.32.243.0/24 permit
|
||||
72.249.147.250/32 permit
|
||||
74.63.63.115 permit
|
||||
74.63.63.121 permit
|
||||
74.63.194.126 permit
|
||||
74.63.234.75 permit
|
||||
74.63.236.0/24 permit
|
||||
74.86.113.28/30 permit
|
||||
74.86.129.240/30 permit
|
||||
74.86.131.208/30 permit
|
||||
74.86.132.208/30 permit
|
||||
74.86.160.160/30 permit
|
||||
74.86.164.188/30 permit
|
||||
74.86.171.192/30 permit
|
||||
74.86.195.28/30 permit
|
||||
74.86.207.36/30 permit
|
||||
74.86.226.216/30 permit
|
||||
74.86.236.240/30 permit
|
||||
74.86.241.250/31 permit
|
||||
74.112.64.26 permit
|
||||
74.112.67.243 permit
|
||||
74.112.170.21/32 permit
|
||||
74.125.0.0/16 permit
|
||||
74.201.84.0/24 permit
|
||||
74.201.152.59/32 permit
|
||||
74.201.154.0/24 permit
|
||||
74.201.155.25/32 permit
|
||||
74.201.155.26/32 permit
|
||||
74.201.155.27/32 permit
|
||||
74.201.155.28/32 permit
|
||||
74.201.155.79/32 permit
|
||||
74.202.227.52/32 permit
|
||||
74.208.4.192/26 permit
|
||||
74.208.5.64/26 permit
|
||||
74.208.122.0/26 permit
|
||||
74.209.250.0/24 permit
|
||||
74.209.250.84 permit
|
||||
75.126.200.128/27 permit
|
||||
75.126.253.0/24 permit
|
||||
75.126.253.48 permit
|
||||
80.231.25.0/24 permit
|
||||
80.231.219.0/24 permit
|
||||
81.223.46.0/27 permit
|
||||
82.165.159.0/24 permit
|
||||
85.222.130.192/26 permit
|
||||
85.222.138.192/26 permit
|
||||
86.61.88.25 permit
|
||||
87.238.80.0/21 permit
|
||||
87.253.232.0/21 permit
|
||||
91.194.248.0/23 permit
|
||||
91.198.22.0/24 permit
|
||||
91.211.240.0/24 permit
|
||||
91.211.242.0/24 permit
|
||||
91.211.243.0/24 permit
|
||||
91.220.42.0/24 permit
|
||||
94.236.119.0/26 permit
|
||||
94.245.112.0/27 permit
|
||||
94.245.112.10/31 permit
|
||||
94.245.120.64/26 permit
|
||||
96.43.144.0/20 permit
|
||||
96.43.144.64/28 permit
|
||||
96.43.144.64/31 permit
|
||||
96.43.147.64/28 permit
|
||||
96.43.148.64/28 permit
|
||||
96.43.148.64/31 permit
|
||||
96.43.151.64/28 permit
|
||||
96.43.152.64/27 permit
|
||||
96.43.153.64/27 permit
|
||||
96.46.150.192/27 permit
|
||||
101.53.164.192/26 permit
|
||||
103.11.200.0/22 permit
|
||||
103.13.69.0/24 permit
|
||||
103.28.42.0/24 permit
|
||||
103.237.104.0/22 permit
|
||||
104.40.211.35 permit
|
||||
104.43.195.251 permit
|
||||
104.47.0.0/17 permit
|
||||
104.130.96.0/28 permit
|
||||
104.130.122.0/23 permit
|
||||
104.245.209.192/26 permit
|
||||
106.50.16.0/28 permit
|
||||
107.0.11.224/27 permit
|
||||
108.174.0.0/24 permit
|
||||
108.174.0.215 permit
|
||||
108.174.3.0/24 permit
|
||||
108.174.6.0/24 permit
|
||||
108.175.18.45 permit
|
||||
108.175.30.45 permit
|
||||
108.177.8.0/21 permit
|
||||
108.177.96.0/19 permit
|
||||
111.221.23.128/25 permit
|
||||
111.221.26.0/27 permit
|
||||
111.221.66.0/25 permit
|
||||
111.221.69.128/25 permit
|
||||
111.221.112.0/21 permit
|
||||
124.47.150.0/24 permit
|
||||
124.47.189.0/24 permit
|
||||
129.41.77.70 permit
|
||||
129.41.169.249 permit
|
||||
131.107.0.0/16 permit
|
||||
131.107.1.18 permit
|
||||
131.107.1.19 permit
|
||||
131.107.1.20 permit
|
||||
131.107.1.37 permit
|
||||
131.107.1.44 permit
|
||||
131.107.1.48 permit
|
||||
131.107.1.56 permit
|
||||
131.253.30.0/24 permit
|
||||
131.253.121.20 permit
|
||||
134.170.113.0/26 permit
|
||||
134.170.140.0/24 permit
|
||||
134.170.141.64/26 permit
|
||||
134.170.143.0/24 permit
|
||||
134.170.174.0/24 permit
|
||||
136.146.128.64/27 permit
|
||||
136.146.208.16/28 permit
|
||||
136.146.210.16/28 permit
|
||||
136.147.46.192/26 permit
|
||||
136.147.62.192/26 permit
|
||||
136.147.128.0/20 permit
|
||||
136.147.176.0/20 permit
|
||||
146.88.28.0/24 permit
|
||||
146.101.78.0/24 permit
|
||||
147.243.1.47 permit
|
||||
147.243.1.48 permit
|
||||
147.243.1.153 permit
|
||||
147.243.128.24 permit
|
||||
147.243.128.26 permit
|
||||
151.101.37.140 permit
|
||||
157.55.0.192/26 permit
|
||||
157.55.1.128/26 permit
|
||||
157.55.2.0/25 permit
|
||||
157.55.9.128/25 permit
|
||||
157.55.11.0/25 permit
|
||||
157.55.49.0/25 permit
|
||||
157.55.61.0/24 permit
|
||||
157.55.157.128/25 permit
|
||||
157.55.158.0/23 permit
|
||||
157.55.225.0/25 permit
|
||||
157.55.234.0/24 permit
|
||||
157.56.24.0/25 permit
|
||||
157.56.110.0/23 permit
|
||||
157.56.112.0/24 permit
|
||||
157.56.120.128/26 permit
|
||||
157.56.172.28 permit
|
||||
157.56.232.0/21 permit
|
||||
157.56.240.0/20 permit
|
||||
157.56.248.0/21 permit
|
||||
157.151.208.65 permit
|
||||
162.88.4.0/24 permit
|
||||
162.88.36.0/24 permit
|
||||
162.248.185.121 permit
|
||||
163.47.180.0/22 permit
|
||||
165.254.167.152/30 permit
|
||||
165.254.167.156/31 permit
|
||||
165.254.167.162/31 permit
|
||||
165.254.168.66/31 permit
|
||||
165.254.168.68/31 permit
|
||||
165.254.168.70/31 permit
|
||||
165.254.168.72/31 permit
|
||||
166.78.68.0/22 permit
|
||||
166.78.68.221 permit
|
||||
166.78.69.146 permit
|
||||
166.78.69.169 permit
|
||||
166.78.69.170 permit
|
||||
166.78.71.131 permit
|
||||
167.89.0.0/17 permit
|
||||
167.89.16.30 permit
|
||||
167.89.16.183 permit
|
||||
167.89.16.245 permit
|
||||
167.89.25.84 permit
|
||||
167.89.32.5 permit
|
||||
167.89.32.50 permit
|
||||
167.89.46.159 permit
|
||||
167.89.46.185 permit
|
||||
167.89.60.95 permit
|
||||
167.89.62.118 permit
|
||||
167.89.64.9 permit
|
||||
167.89.65.0 permit
|
||||
167.89.65.53 permit
|
||||
167.89.65.100 permit
|
||||
167.89.74.233 permit
|
||||
167.89.75.33 permit
|
||||
167.89.75.126 permit
|
||||
167.89.75.136 permit
|
||||
167.89.75.164 permit
|
||||
167.89.101.2 permit
|
||||
167.89.101.192/28 permit
|
||||
167.220.67.238 permit
|
||||
172.217.0.0/19 permit
|
||||
173.0.84.224/28 permit
|
||||
173.0.94.244/30 permit
|
||||
173.193.132.0/23 permit
|
||||
173.193.132.134/31 permit
|
||||
173.193.210.32/27 permit
|
||||
173.194.0.0/16 permit
|
||||
173.203.79.182 permit
|
||||
173.203.81.39 permit
|
||||
173.224.160.128/25 permit
|
||||
173.224.161.128/25 permit
|
||||
173.228.155.0/24 permit
|
||||
174.36.80.208/28 permit
|
||||
174.36.84.8/29 permit
|
||||
174.36.84.16/29 permit
|
||||
174.36.84.32/29 permit
|
||||
174.36.84.144/29 permit
|
||||
174.36.84.240/29 permit
|
||||
174.36.85.248/30 permit
|
||||
174.36.92.96/27 permit
|
||||
174.36.114.128/30 permit
|
||||
174.36.114.140/30 permit
|
||||
174.36.114.148/30 permit
|
||||
174.36.114.152/29 permit
|
||||
174.37.67.28/30 permit
|
||||
174.37.226.64/27 permit
|
||||
174.129.194.241 permit
|
||||
174.129.203.189 permit
|
||||
174.137.46.0/24 permit
|
||||
176.32.105.0/24 permit
|
||||
176.32.127.0/24 permit
|
||||
178.32.48.128 permit
|
||||
178.33.111.144 permit
|
||||
178.33.137.208/28 permit
|
||||
178.33.221.0/24 permit
|
||||
178.236.10.128/26 permit
|
||||
178.249.98.16/29 permit
|
||||
178.249.202.16/29 permit
|
||||
180.189.28.0/24 permit
|
||||
182.50.76.0/22 permit
|
||||
182.50.78.64/28 permit
|
||||
184.173.105.0/24 permit
|
||||
184.173.153.0/24 permit
|
||||
185.4.120.0/24 permit
|
||||
185.4.122.0/24 permit
|
||||
185.12.80.0/22 permit
|
||||
185.28.196.0/22 permit
|
||||
185.90.20.0/22 permit
|
||||
188.172.128.0/20 permit
|
||||
191.239.213.197 permit
|
||||
192.28.128.0/18 permit
|
||||
192.30.252.0/22 permit
|
||||
192.64.236.0/24 permit
|
||||
192.64.237.0/24 permit
|
||||
192.64.238.0/24 permit
|
||||
192.161.144.0/20 permit
|
||||
192.230.81.86 permit
|
||||
192.237.158.0/23 permit
|
||||
192.237.159.42 permit
|
||||
192.237.159.43 permit
|
||||
192.254.112.0/20 permit
|
||||
192.254.112.60 permit
|
||||
192.254.112.98/31 permit
|
||||
192.254.113.10 permit
|
||||
192.254.113.101 permit
|
||||
192.254.114.176 permit
|
||||
192.254.115.72 permit
|
||||
192.254.118.63 permit
|
||||
193.28.178.0/25 permit
|
||||
194.64.234.128/27 permit
|
||||
194.64.234.129 permit
|
||||
194.154.193.192/27 permit
|
||||
195.54.172.0/23 permit
|
||||
195.130.217.0/24 permit
|
||||
198.2.128.0/18 permit
|
||||
198.2.128.0/24 permit
|
||||
198.2.132.0/22 permit
|
||||
198.2.136.0/23 permit
|
||||
198.2.177.0/24 permit
|
||||
198.2.178.0/24 permit
|
||||
198.2.179.0/24 permit
|
||||
198.2.180.0/24 permit
|
||||
198.2.186.0/23 permit
|
||||
198.21.0.0/21 permit
|
||||
198.21.3.166 permit
|
||||
198.21.4.224 permit
|
||||
198.37.144.0/20 permit
|
||||
198.37.145.250 permit
|
||||
198.37.149.128 permit
|
||||
198.37.151.26 permit
|
||||
198.61.254.0/23 permit
|
||||
198.61.254.231 permit
|
||||
198.178.234.57 permit
|
||||
198.245.80.0/20 permit
|
||||
199.15.176.173 permit
|
||||
199.15.212.0/22 permit
|
||||
199.15.214.169/32 permit
|
||||
199.16.156.0/22 permit
|
||||
199.19.0.0/21 permit
|
||||
199.59.148.0/22 permit
|
||||
199.83.132.86 permit
|
||||
199.101.161.130 permit
|
||||
199.101.162.0/25 permit
|
||||
199.122.120.0/21 permit
|
||||
199.127.232.0/22 permit
|
||||
199.187.117.209 permit
|
||||
199.187.117.233 permit
|
||||
199.187.117.234/31 permit
|
||||
199.187.117.236/31 permit
|
||||
199.187.118.201 permit
|
||||
199.187.118.202/31 permit
|
||||
199.187.118.204 permit
|
||||
199.187.118.209 permit
|
||||
199.201.64.23 permit
|
||||
199.201.65.23 permit
|
||||
199.255.192.0/22 permit
|
||||
202.129.242.0/23 permit
|
||||
202.177.148.100 permit
|
||||
202.177.148.110 permit
|
||||
203.32.4.25 permit
|
||||
203.55.21.0/24 permit
|
||||
203.62.195.0/24 permit
|
||||
203.81.17.0/24 permit
|
||||
203.122.32.250 permit
|
||||
203.145.57.160/27 permit
|
||||
204.13.11.48/29 permit
|
||||
204.13.11.48/30 permit
|
||||
204.13.248.0/22 permit
|
||||
204.14.232.0/21 permit
|
||||
204.14.232.64/28 permit
|
||||
204.14.234.64/28 permit
|
||||
204.14.238.0/27 permit
|
||||
204.29.186.0/23 permit
|
||||
204.75.142.0/24 permit
|
||||
204.92.114.187 permit
|
||||
204.92.114.203 permit
|
||||
204.92.114.204/31 permit
|
||||
204.153.121.0/24 permit
|
||||
205.139.110.0/23 permit
|
||||
205.201.128.0/20 permit
|
||||
205.201.131.128/25 permit
|
||||
205.201.132.14 permit
|
||||
205.201.134.128/25 permit
|
||||
205.201.136.0/23 permit
|
||||
205.201.137.229 permit
|
||||
205.201.139.0/24 permit
|
||||
205.201.140.14 permit
|
||||
205.207.104.0/22 permit
|
||||
205.217.25.132 permit
|
||||
205.217.25.135 permit
|
||||
205.251.233.32/32 permit
|
||||
205.251.233.36/32 permit
|
||||
206.25.247.143 permit
|
||||
206.25.247.155 permit
|
||||
206.165.246.80/29 permit
|
||||
206.191.224.0/19 permit
|
||||
206.246.157.1 permit
|
||||
207.46.4.128/25 permit
|
||||
207.46.22.35 permit
|
||||
207.46.22.98 permit
|
||||
207.46.22.101 permit
|
||||
207.46.50.72 permit
|
||||
207.46.50.82 permit
|
||||
207.46.50.192/26 permit
|
||||
207.46.50.224 permit
|
||||
207.46.51.64/26 permit
|
||||
207.46.52.71 permit
|
||||
207.46.52.79 permit
|
||||
207.46.58.128/25 permit
|
||||
207.46.100.0/24 permit
|
||||
207.46.101.128/26 permit
|
||||
207.46.116.128/29 permit
|
||||
207.46.117.0/24 permit
|
||||
207.46.132.128/27 permit
|
||||
207.46.163.0/24 permit
|
||||
207.46.198.0/25 permit
|
||||
207.46.200.0/27 permit
|
||||
207.67.38.0/24 permit
|
||||
207.67.98.192/27 permit
|
||||
207.68.176.0/26 permit
|
||||
207.68.176.96/27 permit
|
||||
207.82.80.0/24 permit
|
||||
207.126.144.0/20 permit
|
||||
207.171.160.0/19 permit
|
||||
207.211.30.0/24 permit
|
||||
207.211.31.0/25 permit
|
||||
207.211.41.113 permit
|
||||
207.218.90.0/24 permit
|
||||
207.250.68.0/24 permit
|
||||
208.40.232.70 permit
|
||||
208.43.21.28/30 permit
|
||||
208.43.21.64/29 permit
|
||||
208.43.21.72/30 permit
|
||||
208.43.239.136/30 permit
|
||||
208.64.132.0/22 permit
|
||||
208.66.139.0/25 permit
|
||||
208.74.204.0/22 permit
|
||||
208.74.204.9 permit
|
||||
208.75.120.0/22 permit
|
||||
208.75.122.246 permit
|
||||
208.76.56.0/21 permit
|
||||
208.78.68.0/22 permit
|
||||
208.82.236.96/28 permit
|
||||
208.82.237.96/28 permit
|
||||
208.82.238.96/28 permit
|
||||
208.85.50.137 permit
|
||||
208.89.13.233 permit
|
||||
208.89.13.234/31 permit
|
||||
208.89.13.236/31 permit
|
||||
208.89.14.201 permit
|
||||
208.89.14.202/31 permit
|
||||
208.89.14.204 permit
|
||||
208.89.14.209 permit
|
||||
208.117.48.0/20 permit
|
||||
208.185.229.45 permit
|
||||
208.201.241.163 permit
|
||||
209.43.22.0/28 permit
|
||||
209.46.117.168 permit
|
||||
209.46.117.179 permit
|
||||
209.61.151.0/24 permit
|
||||
209.67.98.46 permit
|
||||
209.67.98.59 permit
|
||||
209.85.128.0/17 permit
|
||||
212.4.136.0/26 permit
|
||||
212.123.28.40/32 permit
|
||||
212.227.15.0/24 permit
|
||||
212.227.17.0/27 permit
|
||||
212.227.126.128/25 permit
|
||||
213.165.64.0/23 permit
|
||||
213.167.75.0/24 permit
|
||||
213.167.81.0/24 permit
|
||||
213.199.128.139 permit
|
||||
213.199.128.145 permit
|
||||
213.199.138.181 permit
|
||||
213.199.138.191 permit
|
||||
213.199.154.0/24 permit
|
||||
213.199.161.128/27 permit
|
||||
213.199.177.0/26 permit
|
||||
213.199.180.0/24 permit
|
||||
216.17.150.242 permit
|
||||
216.17.150.251 permit
|
||||
216.32.180.0/23 permit
|
||||
216.46.168.197 permit
|
||||
216.46.168.222 permit
|
||||
216.58.192.0/19 permit
|
||||
216.99.5.67 permit
|
||||
216.99.5.68 permit
|
||||
216.113.160.0/24 permit
|
||||
216.113.172.0/25 permit
|
||||
216.113.175.0/24 permit
|
||||
216.136.162.65 permit
|
||||
216.136.162.120/29 permit
|
||||
216.136.168.80/28 permit
|
||||
216.146.32.0/20 permit
|
||||
216.198.0.0/18 permit
|
||||
216.203.30.55 permit
|
||||
216.203.33.178/31 permit
|
||||
216.205.24.0/24 permit
|
||||
216.229.156.0/25 permit
|
||||
216.239.32.0/19 permit
|
||||
217.72.207.0/27 permit
|
||||
217.77.141.52 permit
|
||||
217.77.141.59 permit
|
||||
217.175.193.0/24 permit
|
||||
217.175.194.0/23 permit
|
||||
217.175.196.0/24 permit
|
||||
2001:4860:4000::/36 permit
|
||||
2404:6800:4000::/36 permit
|
||||
2607:f8b0:4000::/36 permit
|
||||
2620:109:c003:104::/64 permit
|
||||
2620:109:c006:104::/64 permit
|
||||
2620:109:c00d:104::/64 permit
|
||||
2620:119:50c0:207::/64 permit
|
||||
2800:3f0:4000::/36 permit
|
6
data/conf/postfix/smtp_dsn_filter
Normal file
6
data/conf/postfix/smtp_dsn_filter
Normal file
@ -0,0 +1,6 @@
|
||||
/^4(\.\d+\.\d+ TLS is required, but host \S+ refused to start TLS: .+)/
|
||||
5$1
|
||||
/^4(\.\d+\.\d+ TLS is required, but was not offered by host .+)/
|
||||
5$1
|
||||
/^4.7.5(.*)/
|
||||
5.7.5$1
|
5
data/conf/postfix/sql/mysql_relay_recipient_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_relay_recipient_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT DISTINCT CASE WHEN '%d' IN (SELECT domain FROM domain WHERE relay_all_recipients=1 AND domain='%d' AND backupmx=1) THEN '%s' ELSE (SELECT goto FROM alias WHERE address='%s' AND active='1') END AS result;
|
5
data/conf/postfix/sql/mysql_tls_enforce_in_policy.cf
Normal file
5
data/conf/postfix/sql/mysql_tls_enforce_in_policy.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT IF( EXISTS( SELECT 'TLS_ACTIVE' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.address WHERE (address='%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain='%d')) AND mailbox.tls_enforce_in = '1' AND mailbox.active = '1'), 'reject_plaintext_session', 'DUNNO') AS 'tls_enforce_in';
|
5
data/conf/postfix/sql/mysql_tls_enforce_out_policy.cf
Normal file
5
data/conf/postfix/sql/mysql_tls_enforce_out_policy.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT IF( EXISTS( SELECT 'TLS_ACTIVE' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.address WHERE (address='%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain='%d')) AND mailbox.tls_enforce_out = '1' AND mailbox.active = '1'), 'smtp_enforced_tls:', 'DUNNO') AS 'tls_enforce_out';
|
@ -0,0 +1,6 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
|
||||
|
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
|
5
data/conf/postfix/sql/mysql_virtual_alias_domain_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_alias_domain_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
|
5
data/conf/postfix/sql/mysql_virtual_alias_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_alias_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1';
|
5
data/conf/postfix/sql/mysql_virtual_domains_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_domains_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1' UNION SELECT domain FROM domain WHERE domain='%s' AND active = '1' AND backupmx = '0'
|
5
data/conf/postfix/sql/mysql_virtual_mailbox_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_mailbox_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
|
5
data/conf/postfix/sql/mysql_virtual_relay_domain_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_relay_domain_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
|
5
data/conf/postfix/sql/mysql_virtual_sender_acl.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_sender_acl.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1' AND domain IN(SELECT domain FROM domain WHERE domain='%d' AND active='1') UNION SELECT logged_in_as FROM sender_acl WHERE send_as='@%d' OR send_as='%s' OR send_as IN ( SELECT CONCAT ('@',target_domain) FROM alias_domain WHERE alias_domain = '%d') OR send_as IN ( SELECT CONCAT ('%u','@',target_domain) FROM alias_domain WHERE alias_domain = '%d' ) AND logged_in_as NOT IN (SELECT goto FROM alias WHERE address='%s') UNION SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' AND alias.address = CONCAT('%u','@',alias_domain.target_domain) AND alias.active ='1' AND alias_domain.active='1'
|
5
data/conf/postfix/sql/mysql_virtual_spamalias_maps.cf
Normal file
5
data/conf/postfix/sql/mysql_virtual_spamalias_maps.cf
Normal file
@ -0,0 +1,5 @@
|
||||
user = mailcow
|
||||
password = mysafepasswd
|
||||
hosts = mysql
|
||||
dbname = mailcow
|
||||
query = SELECT goto FROM spamalias WHERE address='%s' AND validity >= UNIX_TIMESTAMP()
|
42
data/conf/rmilter/rmilter.conf
Normal file
42
data/conf/rmilter/rmilter.conf
Normal file
@ -0,0 +1,42 @@
|
||||
bind_socket = inet:9900;
|
||||
spamd {
|
||||
servers = r:rspamd:11333;
|
||||
connect_timeout = 1s;
|
||||
results_timeout = 20s;
|
||||
error_time = 10;
|
||||
dead_time = 300;
|
||||
maxerrors = 10;
|
||||
reject_message = "Spam or virus message rejected due to high detection score";
|
||||
whitelist = 127.0.0.1/32, [::1]/128;
|
||||
spamd_soft_fail = yes;
|
||||
rspamd_metric = "default";
|
||||
extended_spam_headers = yes;
|
||||
spam_header = "X-Spam-Flag";
|
||||
spam_header_value = "YES";
|
||||
};
|
||||
redis {
|
||||
servers_grey = redis:6379;
|
||||
servers_limits = redis:6379;
|
||||
servers_id = redis:6379;
|
||||
id_prefix = "message_id.";
|
||||
grey_prefix = "grey.";
|
||||
white_prefix = "white.";
|
||||
connect_timeout = 1s;
|
||||
error_time = 10;
|
||||
dead_time = 300;
|
||||
maxerrors = 10;
|
||||
};
|
||||
tempdir = /tmp;
|
||||
tempfiles_mode = 00600;
|
||||
max_size = 20M;
|
||||
strict_auth = yes;
|
||||
use_dcc = no;
|
||||
limits {
|
||||
enable = false;
|
||||
};
|
||||
greylisting {
|
||||
enable = false;
|
||||
}
|
||||
dkim {
|
||||
enable = false;
|
||||
};
|
22
data/conf/rspamd/dynmaps/authoritative.php
Normal file
22
data/conf/rspamd/dynmaps/authoritative.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
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,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
$stmt = $pdo->query("SELECT `domain` FROM `domain`");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
echo strtolower(trim($row['domain'])) . PHP_EOL;
|
||||
}
|
||||
$stmt = $pdo->query("SELECT `alias_domain` FROM `alias_domain`");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
echo strtolower(trim($row['alias_domain'])) . PHP_EOL;
|
||||
}
|
||||
?>
|
224
data/conf/rspamd/dynmaps/settings.php
Normal file
224
data/conf/rspamd/dynmaps/settings.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/*
|
||||
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,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
?>
|
||||
settings {
|
||||
<?php
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
score_<?=$username_sane;?> {
|
||||
priority = low;
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf`
|
||||
WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel')
|
||||
AND `object`= :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$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 OR `object`= :object_domain)
|
||||
AND (`option` = 'blacklist_from' OR `option` = 'whitelist_from')");
|
||||
$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])));
|
||||
?>
|
||||
from = "/^((?!<?=$value_sane;?>).)*$/";
|
||||
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_1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row_aliases_1 = array_shift($rows_aliases_1)) {
|
||||
?>
|
||||
rcpt = "<?=$row_aliases_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_2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
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" {
|
||||
actions {
|
||||
reject = <?=$spamscore['highspamlevel'][0];?>;
|
||||
greylist = <?=$spamscore['lowspamlevel'][0] - 1;?>;
|
||||
"add header" = <?=$spamscore['lowspamlevel'][0];?>;
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start whitelist
|
||||
*/
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
whitelist_<?=$username_sane;?> {
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(`value`, '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
AND `option` = 'whitelist_from'");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
|
||||
?>
|
||||
from = "/(<?=$value_sane;?>)/";
|
||||
<?php
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
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'];?>/";
|
||||
<?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'];?>";
|
||||
<?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);
|
||||
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" {
|
||||
MAILCOW_MOO = -999.0;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start blacklist
|
||||
*/
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
blacklist_<?=$username_sane;?> {
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(REPLACE(`value`, '*', '.*') SEPARATOR '|') AS `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
AND `option` = 'blacklist_from'");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
|
||||
?>
|
||||
from = "/(<?=$value_sane;?>)/";
|
||||
<?php
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
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'];?>/";
|
||||
<?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_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_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_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_bl_2['aliases'];?>";
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
MAILCOW_MOO = 999.0;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
}
|
22
data/conf/rspamd/dynmaps/tags.php
Normal file
22
data/conf/rspamd/dynmaps/tags.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
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,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
$stmt = $pdo->query("SELECT `username` FROM `mailbox` WHERE `wants_tagged_subject` = '1'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
echo strtolower(trim($row['username'])) . PHP_EOL;
|
||||
}
|
||||
$stmt = $pdo->query("SELECT CONCAT(mailbox.local_part, '@', alias_domain.alias_domain) as `tag_ad` FROM `mailbox` INNER JOIN `alias_domain` ON mailbox.domain = alias_domain.target_domain WHERE mailbox.wants_tagged_subject='1';");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
echo strtolower(trim($row['tag_ad'])) . PHP_EOL;
|
||||
}
|
||||
?>
|
1
data/conf/rspamd/dynmaps/vars.inc.php
Symbolic link
1
data/conf/rspamd/dynmaps/vars.inc.php
Symbolic link
@ -0,0 +1 @@
|
||||
../../../web/inc/vars.inc.php
|
34
data/conf/rspamd/local.d/dkim.conf
Normal file
34
data/conf/rspamd/local.d/dkim.conf
Normal file
@ -0,0 +1,34 @@
|
||||
sign_condition =<<EOD
|
||||
return function(task)
|
||||
local smtp_from = task:get_from('smtp')
|
||||
local mime_from = task:get_from('mime')
|
||||
local rspamd_logger = require "rspamd_logger"
|
||||
if smtp_from[1]['domain'] ~= nil and smtp_from[1]['domain'] ~= '' then
|
||||
domain = smtp_from[1]['domain']
|
||||
rspamd_logger.infox(task, "set domain found in smtp from field to %s", domain)
|
||||
if not task:get_user() then
|
||||
rspamd_logger.infox(task, "found domain in smtp header field, but user is not authenticated - skipped")
|
||||
return false
|
||||
end
|
||||
elseif mime_from[1]['domain'] ~= nil and mime_from[1]['domain'] ~= '' then
|
||||
domain = mime_from[1]['domain']
|
||||
rspamd_logger.infox(task, "set domain found in mime from field to %s", domain)
|
||||
else
|
||||
rspamd_logger.infox(task, "cannot determine domain for dkim signing")
|
||||
return false
|
||||
end
|
||||
local keyfile = io.open("/data/dkim/keys/" .. domain .. ".dkim")
|
||||
if keyfile then
|
||||
rspamd_logger.infox(task, "found dkim key file for domain %s", domain)
|
||||
keyfile:close()
|
||||
return {
|
||||
key = "/data/dkim/keys/" .. domain .. ".dkim",
|
||||
domain = domain,
|
||||
selector = "dkim"
|
||||
}
|
||||
else
|
||||
rspamd_logger.infox(task, "no key file for domain %s - skipped", domain)
|
||||
end
|
||||
return false
|
||||
end
|
||||
EOD;
|
19
data/conf/rspamd/local.d/metrics.conf
Normal file
19
data/conf/rspamd/local.d/metrics.conf
Normal file
@ -0,0 +1,19 @@
|
||||
actions {
|
||||
reject = 15;
|
||||
add_header = 5;
|
||||
greylist = 4;
|
||||
}
|
||||
symbol "MAILCOW_AUTH" {
|
||||
description = "mailcow authenticated";
|
||||
score = -20.0;
|
||||
}
|
||||
group "bayes" {
|
||||
symbol "BAYES_SPAM" {
|
||||
weight = 7.5;
|
||||
description = "Message probably spam, probability: ";
|
||||
}
|
||||
symbol "BAYES_HAM" {
|
||||
weight = -2.5;
|
||||
description = "Message probably ham, probability: ";
|
||||
}
|
||||
}
|
3
data/conf/rspamd/local.d/options.inc
Normal file
3
data/conf/rspamd/local.d/options.inc
Normal file
@ -0,0 +1,3 @@
|
||||
dns {
|
||||
enable_dnssec = true;
|
||||
}
|
1
data/conf/rspamd/local.d/redis.conf
Normal file
1
data/conf/rspamd/local.d/redis.conf
Normal file
@ -0,0 +1 @@
|
||||
servers = "redis:6379";
|
1
data/conf/rspamd/local.d/rspamd.conf.local
Normal file
1
data/conf/rspamd/local.d/rspamd.conf.local
Normal file
@ -0,0 +1 @@
|
||||
# rspamd.conf.local
|
59
data/conf/rspamd/local.d/statistic.conf
Normal file
59
data/conf/rspamd/local.d/statistic.conf
Normal file
@ -0,0 +1,59 @@
|
||||
classifier "bayes" {
|
||||
tokenizer {
|
||||
name = "osb";
|
||||
}
|
||||
|
||||
backend = "redis";
|
||||
servers = "redis:6379";
|
||||
min_tokens = 11;
|
||||
min_learns = 20;
|
||||
autolearn = true;
|
||||
|
||||
per_user = <<EOD
|
||||
return function(task)
|
||||
local rcpt = task:get_recipients(1)
|
||||
|
||||
if rcpt then
|
||||
one_rcpt = rcpt[1]
|
||||
if one_rcpt['domain'] then
|
||||
return one_rcpt['domain']
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
EOD
|
||||
|
||||
statfile {
|
||||
symbol = "BAYES_HAM";
|
||||
spam = false;
|
||||
}
|
||||
statfile {
|
||||
symbol = "BAYES_SPAM";
|
||||
spam = true;
|
||||
}
|
||||
learn_condition =<<EOD
|
||||
return function(task, is_spam, is_unlearn)
|
||||
local prob = task:get_mempool():get_variable('bayes_prob', 'double')
|
||||
|
||||
if prob then
|
||||
local in_class = false
|
||||
local cl
|
||||
if is_spam then
|
||||
cl = 'spam'
|
||||
in_class = prob >= 0.95
|
||||
else
|
||||
cl = 'ham'
|
||||
in_class = prob <= 0.05
|
||||
end
|
||||
|
||||
if in_class then
|
||||
return false,string.format('already in class %s; probability %.2f%%',
|
||||
cl, math.abs((prob - 0.5) * 200.0))
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
EOD
|
||||
}
|
75
data/conf/rspamd/lua/rspamd.local.lua
Normal file
75
data/conf/rspamd/lua/rspamd.local.lua
Normal file
@ -0,0 +1,75 @@
|
||||
rspamd_config.MAILCOW_AUTH = {
|
||||
callback = function(task)
|
||||
local uname = task:get_user()
|
||||
if uname then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
rspamd_config.MAILCOW_MOO = function (task)
|
||||
return true
|
||||
end
|
||||
|
||||
local modify_subject_map = rspamd_config:add_map({
|
||||
url = 'http://nginx:8081/tags.php',
|
||||
type = 'map',
|
||||
description = 'Map of users to use subject tags for'
|
||||
})
|
||||
|
||||
local auth_domain_map = rspamd_config:add_map({
|
||||
url = 'http://nginx:8081/authoritative.php',
|
||||
type = 'map',
|
||||
description = 'Map of domains we are authoritative for'
|
||||
})
|
||||
|
||||
rspamd_config.ADD_DELIMITER_TAG = {
|
||||
callback = function(task)
|
||||
local util = require("rspamd_util")
|
||||
local rspamd_logger = require "rspamd_logger"
|
||||
|
||||
local user_env_tagged = task:get_recipients(1)[1]['user']
|
||||
local user_to_tagged = task:get_recipients(2)[1]['user']
|
||||
|
||||
local domain = task:get_recipients(1)[1]['domain']
|
||||
|
||||
local user_env, tag_env = user_env_tagged:match("([^+]+)+(.*)")
|
||||
local user_to, tag_to = user_to_tagged:match("([^+]+)+(.*)")
|
||||
|
||||
local authdomain = auth_domain_map:get_key(domain)
|
||||
|
||||
if tag_env then
|
||||
tag = tag_env
|
||||
user = user_env
|
||||
elseif tag_to then
|
||||
tag = tag_to
|
||||
user = user_env
|
||||
end
|
||||
|
||||
if tag and authdomain then
|
||||
rspamd_logger.infox("Domain %s is part of mailcow, start reading tag settings", domain)
|
||||
local user_untagged = user .. '@' .. domain
|
||||
rspamd_logger.infox("Querying tag settings for user %1", user_untagged)
|
||||
if modify_subject_map:get_key(user_untagged) then
|
||||
rspamd_logger.infox("User wants subject modified for tagged mail")
|
||||
local sbj = task:get_header('Subject')
|
||||
if tag then
|
||||
rspamd_logger.infox("Found tag %1, will modify subject header", tag)
|
||||
new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
|
||||
task:set_rmilter_reply({
|
||||
remove_headers = {['Subject'] = 1},
|
||||
add_headers = {['Subject'] = new_sbj}
|
||||
})
|
||||
end
|
||||
else
|
||||
rspamd_logger.infox("Add X-Moo-Tag header")
|
||||
task:set_rmilter_reply({
|
||||
add_headers = {['X-Moo-Tag'] = 'YES'}
|
||||
})
|
||||
end
|
||||
else
|
||||
rspamd_logger.infox("Skip delimiter handling for untagged message or authenticated user")
|
||||
end
|
||||
return false
|
||||
end
|
||||
}
|
3
data/conf/rspamd/override.d/logging.inc
Normal file
3
data/conf/rspamd/override.d/logging.inc
Normal file
@ -0,0 +1,3 @@
|
||||
type = "console";
|
||||
systemd = false;
|
||||
.include "$CONFDIR/logging.inc"
|
7
data/conf/rspamd/override.d/worker-controller.inc
Normal file
7
data/conf/rspamd/override.d/worker-controller.inc
Normal file
@ -0,0 +1,7 @@
|
||||
bind_socket = "*:11334";
|
||||
enable_password = "$2$pppq86q9uns51zd5ekfxecj7bxwaefo3$p7f9xdhamydjhtypcr639it3kqeiknx3dk9on7skjypyi8uwwcmy";
|
||||
secure_ip = "192.168.0.0/16";
|
||||
secure_ip = "172.16.0.0/12";
|
||||
secure_ip = "10.0.0.0/8";
|
||||
secure_ip = "127.0.0.1";
|
||||
secure_ip = "::1";
|
1
data/conf/rspamd/override.d/worker-normal.inc
Normal file
1
data/conf/rspamd/override.d/worker-normal.inc
Normal file
@ -0,0 +1 @@
|
||||
bind_socket = "*:11333";
|
76
data/conf/sogo/sogo.conf
Normal file
76
data/conf/sogo/sogo.conf
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
SOGoCalendarDefaultRoles = (
|
||||
PublicViewer,
|
||||
ConfidentialDAndTViewer,
|
||||
PrivateDAndTViewer
|
||||
);
|
||||
|
||||
WOWorkersCount = "20";
|
||||
SOGoACLsSendEMailNotifications = YES;
|
||||
SOGoAppointmentSendEMailNotifications = YES;
|
||||
SOGoDraftsFolderName = "Drafts";
|
||||
SOGoJunkFolderName= "Junk";
|
||||
SOGoMailDomain = "sogo.local";
|
||||
SOGoEnableEMailAlarms = NO;
|
||||
SOGoFoldersSendEMailNotifications = YES;
|
||||
SOGoForwardEnabled = YES;
|
||||
|
||||
// Multi-domain setup
|
||||
// Domains are isolated, you can define visibility options here.
|
||||
// Example:
|
||||
|
||||
// SOGoDomainsVisibility = (
|
||||
// (domain1.tld, domain5.tld),
|
||||
// (domain3.tld, domain2.tld)
|
||||
// );
|
||||
|
||||
SOGoIMAPServer = "imap://dovecot:143/?tls=YES";
|
||||
SOGoSieveServer = "sieve://dovecot:4190/?tls=YES";
|
||||
SOGoSMTPServer = "postfix:588";
|
||||
WOPort = "0.0.0.0:20000";
|
||||
SOGoMemcachedHost = "memcached";
|
||||
|
||||
SOGoLanguage = English;
|
||||
SOGoMailAuxiliaryUserAccountsEnabled = YES;
|
||||
SOGoMailCustomFromEnabled = YES;
|
||||
SOGoMailingMechanism = smtp;
|
||||
SOGoSMTPAuthenticationType = plain;
|
||||
|
||||
SxVMemLimit = 512;
|
||||
|
||||
SOGoMaximumPingInterval = 354;
|
||||
|
||||
SOGoInternalSyncInterval = 30;
|
||||
SOGoMaximumSyncInterval = 354;
|
||||
|
||||
SOGoMaximumSyncWindowSize = 0;
|
||||
SOGoMaximumSyncResponseSize = 1024;
|
||||
|
||||
WOWatchDogRequestTimeout = 10;
|
||||
WOListenQueueSize = 300;
|
||||
WONoDetach = YES;
|
||||
|
||||
SOGoIMAPAclConformsToIMAPExt = Yes;
|
||||
SOGoPageTitle = "SOGo Groupware";
|
||||
SOGoFirstDayOfWeek = "1";
|
||||
|
||||
SOGoSieveFolderEncoding = "UTF-8";
|
||||
SOGoPasswordChangeEnabled = NO;
|
||||
SOGoSentFolderName = "Sent";
|
||||
SOGoMailShowSubscribedFoldersOnly = NO;
|
||||
NGImap4ConnectionStringSeparator = "/";
|
||||
SOGoSieveScriptsEnabled = YES;
|
||||
SOGoTrashFolderName = "Trash";
|
||||
SOGoVacationEnabled = YES;
|
||||
|
||||
MySQL4Encoding = "utf8mb4";
|
||||
//SOGoDebugRequests = YES;
|
||||
//SoDebugBaseURL = YES;
|
||||
//ImapDebugEnabled = YES;
|
||||
//SOGoEASDebugEnabled = YES;
|
||||
//LDAPDebugEnabled = YES;
|
||||
//PGDebugEnabled = YES;
|
||||
//MySQL4DebugEnabled = YES;
|
||||
//SOGoUIxDebugEnabled = YES;
|
||||
//WODontZipResponse = YES;
|
||||
}
|
385
data/web/add.php
Normal file
385
data/web/add.php
Normal file
@ -0,0 +1,385 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
}
|
||||
require_once("inc/header.inc.php");
|
||||
?>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['add']['title'];?></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
if (isset($_GET['domain']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||
?>
|
||||
<h4><?=$lang['add']['domain'];?></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="domain"><?=$lang['add']['domain'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" autocorrect="off" autocapitalize="none" class="form-control" name="domain" id="domain">
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="aliases"><?=$lang['add']['max_aliases'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="aliases" id="aliases" value="400">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="mailboxes"><?=$lang['add']['max_mailboxes'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="mailboxes" id="mailboxes" value="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="maxquota"><?=$lang['add']['mailbox_quota_m'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="maxquota" id="maxquota" value="3072">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="quota"><?=$lang['add']['domain_quota_m'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" name="quota" id="quota" value="10240">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2"><?=$lang['add']['backup_mx_options'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="backupmx"> <?=$lang['add']['relay_domain'];?></label>
|
||||
<br />
|
||||
<label><input type="checkbox" name="relay_all_recipients"> <?=$lang['add']['relay_all'];?></label>
|
||||
<p><?=$lang['add']['relay_all_info'];?></p>
|
||||
</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="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>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
elseif (isset($_GET['alias'])) {
|
||||
?>
|
||||
<h4><?=$lang['add']['alias'];?></h4>
|
||||
<p><?=$lang['add']['alias_spf_fail'];?></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="address"><?=$lang['add']['alias_address'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="address" id="address"></textarea>
|
||||
<p><?=$lang['add']['alias_address_info'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="goto"><?=$lang['add']['target_address'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto"></textarea>
|
||||
<p><?=$lang['add']['target_address_info'];?></p>
|
||||
</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="mailbox_add_alias" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
elseif (isset($_GET['aliasdomain'])) {
|
||||
?>
|
||||
<h4><?=$lang['add']['alias_domain'];?></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="alias_domain"><?=$lang['add']['alias_domain'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="alias_domain" id="alias_domain"></textarea>
|
||||
<p><?=$lang['add']['alias_domain_info'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
<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'];?>" required>
|
||||
<?php
|
||||
foreach (mailbox_get_domains() as $domain) {
|
||||
echo "<option>".htmlspecialchars($domain)."</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">
|
||||
<button type="submit" name="mailbox_add_alias_domain" class="btn btn-success "><?=$lang['add']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
elseif (isset($_GET['mailbox'])) {
|
||||
?>
|
||||
<h4><?=$lang['add']['mailbox'];?></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="local_part"><?=$lang['add']['mailbox_username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" pattern="[A-Za-z0-9\.!#$%&'*+/=?^_`{|}~-]+" autocorrect="off" autocapitalize="none" class="form-control" name="local_part" id="local_part" 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 id="addSelectDomain" 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="name"><?=$lang['add']['full_name'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="name" id="name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="addInputQuota"><?=$lang['add']['quota_mb'];?>
|
||||
<br /><span id="quotaBadge" class="badge">max. - MiB</span>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="quota" min="1" max="" id="addInputQuota" disabled value="<?=$lang['add']['select_domain'];?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="password"><?=$lang['add']['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['add']['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['add']['active'];?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<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>
|
||||
<?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'])) {
|
||||
?>
|
||||
<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>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="<?=$_SESSION['return_to'];?>">← <?=$lang['add']['previous'];?></a>
|
||||
</div> <!-- /container -->
|
||||
<script src="js/add.js"></script>
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
?>
|
311
data/web/admin.php
Normal file
311
data/web/admin.php
Normal file
@ -0,0 +1,311 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||
require_once("inc/header.inc.php");
|
||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||
$tfa_data = get_tfa();
|
||||
?>
|
||||
<div class="container">
|
||||
<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 $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 id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
|
||||
<div id="tfa_additional">
|
||||
<?php if($tfa_data['additional']):
|
||||
foreach ($tfa_data['additional'] as $key_info): ?>
|
||||
<form style="display:inline;" method="post">
|
||||
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
|
||||
<div style="padding:4px;margin:4px" class="label label-<?=($_SESSION['tfa_id'] == $key_info['id']) ? 'success' : 'default'; ?>">
|
||||
<?=$key_info['key_id'];?>
|
||||
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=strtolower($lang['admin']['remove']);?>]</a>
|
||||
</div>
|
||||
</form>
|
||||
<?php endforeach;
|
||||
endif;?>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?>:</div>
|
||||
<div class="col-sm-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
|
||||
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>
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
} else {
|
||||
header('Location: /');
|
||||
exit();
|
||||
}
|
||||
?>
|
69
data/web/autoconfig.php
Normal file
69
data/web/autoconfig.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
require_once "inc/vars.inc.php";
|
||||
if (empty($mailcow_hostname)) { exit(); }
|
||||
header("Content-Type: application/xml");
|
||||
?>
|
||||
<?='<?xml version="1.0"?>';?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="<?=$mailcow_hostname;?>">
|
||||
|
||||
<displayName>A mailcow mail server</displayName>
|
||||
<displayShortName>mail server</displayShortName>
|
||||
|
||||
<incomingServer type="imap">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<incomingServer type="imap">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>143</port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
|
||||
<incomingServer type="pop3">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>995</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<incomingServer type="pop3">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>110</port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</outgoingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname><?=$mailcow_hostname;?></hostname>
|
||||
<port>587</port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</outgoingServer>
|
||||
|
||||
<enable visiturl="https://<?=$mailcow_hostname;?>/admin.php">
|
||||
<instruction>If you didn't change the password given to you by the administrator or if you didn't change it in a long time, please consider doing that now.</instruction>
|
||||
<instruction lang="de">Sollten Sie das Ihnen durch den Administrator vergebene Passwort noch nicht geändert haben, empfehlen wir dies nun zu tun. Auch ein altes Passwort sollte aus Sicherheitsgründen geändert werden.</instruction>
|
||||
</enable>
|
||||
|
||||
</emailProvider>
|
||||
|
||||
<webMail>
|
||||
<loginPage url="https://<?=$mailcow_hostname;?>/SOGo/" />
|
||||
</webMail>
|
||||
</clientConfig>
|
142
data/web/autodiscover.php
Normal file
142
data/web/autodiscover.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
require_once 'inc/vars.inc.php';
|
||||
require_once 'inc/functions.inc.php';
|
||||
|
||||
ini_set('error_reporting', '0');
|
||||
$config = array(
|
||||
'useEASforOutlook' => 'yes',
|
||||
'autodiscoverType' => 'activesync',
|
||||
'imap' => array(
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => '993',
|
||||
'ssl' => 'on',
|
||||
),
|
||||
'smtp' => array(
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => '465',
|
||||
'ssl' => 'on'
|
||||
),
|
||||
'activesync' => array(
|
||||
'url' => 'https://'.$mailcow_hostname.'/Microsoft-Server-ActiveSync'
|
||||
)
|
||||
);
|
||||
|
||||
if(file_exists('inc/vars.local.inc.php')) {
|
||||
include_once 'inc/vars.local.inc.php';
|
||||
}
|
||||
|
||||
/* ---------- DO NOT MODIFY ANYTHING BEYOND THIS LINE. IGNORE AT YOUR OWN RISK. ---------- */
|
||||
|
||||
if ($config['useEASforOutlook'] == 'no') {
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Outlook')) {
|
||||
$config['autodiscoverType'] = 'imap';
|
||||
}
|
||||
}
|
||||
|
||||
$dsn = "$database_type:host=$database_host;dbname=$database_name";
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
$login_user = strtolower(trim($_SERVER['PHP_AUTH_USER']));
|
||||
$as = check_login($login_user, $_SERVER['PHP_AUTH_PW']);
|
||||
|
||||
if (!isset($_SERVER['PHP_AUTH_USER']) OR $as !== "user") {
|
||||
header('WWW-Authenticate: Basic realm=""');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
exit;
|
||||
} else {
|
||||
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
if ($as === "user") {
|
||||
header("Content-Type: application/xml");
|
||||
echo '<?xml version="1.0" encoding="utf-8" ?><Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">';
|
||||
|
||||
$data = trim(file_get_contents("php://input"));
|
||||
if(!$data) {
|
||||
list($usec, $sec) = explode(' ', microtime());
|
||||
echo '<Response>';
|
||||
echo '<Error Time="' . date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2) . '" Id="2477272013">';
|
||||
echo '<ErrorCode>600</ErrorCode><Message>Invalid Request</Message><DebugData /></Error>';
|
||||
echo '</Response>';
|
||||
echo '</Autodiscover>';
|
||||
exit(0);
|
||||
}
|
||||
$discover = new SimpleXMLElement($data);
|
||||
$email = $discover->Request->EMailAddress;
|
||||
|
||||
if ($config['autodiscoverType'] == 'imap') {
|
||||
?>
|
||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>settings</Action>
|
||||
<Protocol>
|
||||
<Type>IMAP</Type>
|
||||
<Server><?php echo $config['imap']['server']; ?></Server>
|
||||
<Port><?php echo $config['imap']['port']; ?></Port>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName><?php echo $email; ?></LoginName>
|
||||
<SPA>off</SPA>
|
||||
<SSL><?php echo $config['imap']['ssl']; ?></SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>SMTP</Type>
|
||||
<Server><?php echo $config['smtp']['server']; ?></Server>
|
||||
<Port><?php echo $config['smtp']['port']; ?></Port>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName><?php echo $email; ?></LoginName>
|
||||
<SPA>off</SPA>
|
||||
<SSL><?php echo $config['smtp']['ssl']; ?></SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
<UsePOPAuth>on</UsePOPAuth>
|
||||
<SMTPLast>off</SMTPLast>
|
||||
</Protocol>
|
||||
</Account>
|
||||
</Response>
|
||||
<?php
|
||||
}
|
||||
else if ($config['autodiscoverType'] == 'activesync') {
|
||||
$username = trim($email);
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
die("Failed to determine name from SQL");
|
||||
}
|
||||
if (!empty($MailboxData['name'])) {
|
||||
$displayname = utf8_encode($MailboxData['name']);
|
||||
}
|
||||
else {
|
||||
$displayname = $email;
|
||||
}
|
||||
?>
|
||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
|
||||
<Culture>en:en</Culture>
|
||||
<User>
|
||||
<DisplayName><?php echo $displayname; ?></DisplayName>
|
||||
<EMailAddress><?php echo $email; ?></EMailAddress>
|
||||
</User>
|
||||
<Action>
|
||||
<Settings>
|
||||
<Server>
|
||||
<Type>MobileSync</Type>
|
||||
<Url><?php echo $config['activesync']['url']; ?></Url>
|
||||
<Name><?php echo $config['activesync']['url']; ?></Name>
|
||||
</Server>
|
||||
</Settings>
|
||||
</Action>
|
||||
</Response>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</Autodiscover>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
40
data/web/call_sogo_ctrl.php
Normal file
40
data/web/call_sogo_ctrl.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
session_start();
|
||||
$AuthUsers = array("admin");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
echo "Not allowed." . PHP_EOL;
|
||||
exit();
|
||||
}
|
||||
if ($_GET['ACTION'] == "start") {
|
||||
$request = xmlrpc_encode_request("supervisor.startProcessGroup", 'sogo-group', array('encoding'=>'utf-8'));
|
||||
$context = stream_context_create(array('http' => array(
|
||||
'method' => "POST",
|
||||
'header' => "Content-Length: " . strlen($request),
|
||||
'content' => $request
|
||||
)));
|
||||
$file = @file_get_contents("http://sogo:9191/RPC2", false, $context) or die("Cannot connect to $remote_server:$listener_port");
|
||||
$response = xmlrpc_decode($file);
|
||||
if (isset($response['faultString'])) {
|
||||
echo '<b><span class="pull-right text-warning">' . $response['faultString'] . '</span></b>';
|
||||
}
|
||||
else {
|
||||
echo '<b><span class="pull-right text-success">OK</span></b>';
|
||||
}
|
||||
}
|
||||
elseif ($_GET['ACTION'] == "stop") {
|
||||
$request = xmlrpc_encode_request("supervisor.stopProcessGroup", 'sogo-group', array('encoding'=>'utf-8'));
|
||||
$context = stream_context_create(array('http' => array(
|
||||
'method' => "POST",
|
||||
'header' => "Content-Length: " . strlen($request),
|
||||
'content' => $request
|
||||
)));
|
||||
$file = @file_get_contents("http://sogo:9191/RPC2", false, $context) or die("Cannot connect to $remote_server:$listener_port");
|
||||
$response = xmlrpc_decode($file);
|
||||
if (isset($response['faultString'])) {
|
||||
echo '<b><span class="pull-right text-warning">' . $response['faultString'] . '</span></b>';
|
||||
}
|
||||
else {
|
||||
echo '<b><span class="pull-right text-success">OK</span></b>';
|
||||
}
|
||||
}
|
||||
?>
|
6
data/web/css/bootstrap-select.min.css
vendored
Normal file
6
data/web/css/bootstrap-select.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
41
data/web/css/bootstrap-slider.min.css
vendored
Normal file
41
data/web/css/bootstrap-slider.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
10
data/web/css/bootstrap-switch.min.css
vendored
Normal file
10
data/web/css/bootstrap-switch.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
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;
|
||||
}
|
212
data/web/delete.php
Normal file
212
data/web/delete.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
}
|
||||
require_once("inc/header.inc.php");
|
||||
?>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['delete']['title'];?></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
// DELETE DOMAIN
|
||||
if (isset($_GET["domain"]) &&
|
||||
is_valid_domain_name($_GET["domain"]) &&
|
||||
!empty($_GET["domain"]) &&
|
||||
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$domain = $_GET["domain"];
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_domain_warning'], htmlspecialchars($_GET["domain"]));?></div>
|
||||
<p><?=$lang['delete']['remove_domain_details'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
|
||||
<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="mailbox_delete_domain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
// DELETE ALIAS
|
||||
elseif (isset($_GET["alias"]) &&
|
||||
(filter_var($_GET["alias"], FILTER_VALIDATE_EMAIL) || is_valid_domain_name(substr(strrchr($_GET["alias"], "@"), 1))) &&
|
||||
!empty($_GET["alias"])) {
|
||||
$domain = substr(strrchr($_GET["alias"], "@"), 1);
|
||||
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
|
||||
?>
|
||||
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_alias_warning'], htmlspecialchars($_GET["alias"]));?></div>
|
||||
<p><?=$lang['delete']['remove_alias_details'];?></p>
|
||||
<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
|
||||
<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="mailbox_delete_alias" 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 ALIAS DOMAIN
|
||||
elseif (
|
||||
isset($_GET["aliasdomain"]) &&
|
||||
is_valid_domain_name($_GET["aliasdomain"]) &&
|
||||
!empty($_GET["aliasdomain"])) {
|
||||
$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="mailbox_delete_alias_domain" 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 DOMAIN ADMIN
|
||||
elseif (isset($_GET["domainadmin"]) &&
|
||||
ctype_alnum(str_replace(array('_', '.', '-'), '', $_GET["domainadmin"])) &&
|
||||
!empty($_GET["domainadmin"]) &&
|
||||
$_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>
|
||||
<form class="form-horizontal" role="form" method="post" action="/admin.php">
|
||||
<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="delete_domain_admin" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
// DELETE MAILBOX
|
||||
elseif (isset($_GET["mailbox"]) &&
|
||||
filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) &&
|
||||
!empty($_GET["mailbox"])) {
|
||||
$mailbox = $_GET["mailbox"];
|
||||
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($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="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>
|
||||
<?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
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-danger" role="alert"><?=$lang['danger']['access_denied'];?></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="<?=$_SESSION['return_to'];?>">← <?=$lang['delete']['previous'];?></a>
|
||||
</div> <!-- /container -->
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
?>
|
664
data/web/edit.php
Normal file
664
data/web/edit.php
Normal file
@ -0,0 +1,664 @@
|
||||
<?php
|
||||
require_once("inc/prerequisites.inc.php");
|
||||
$AuthUsers = array("admin", "domainadmin", "user");
|
||||
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
|
||||
header('Location: /');
|
||||
exit();
|
||||
}
|
||||
require_once("inc/header.inc.php");
|
||||
?>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?=$lang['edit']['title'];?></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php
|
||||
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
|
||||
if (isset($_GET["alias"]) &&
|
||||
!empty($_GET["alias"])) {
|
||||
$alias = $_GET["alias"];
|
||||
$result = mailbox_get_alias_details($alias);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['alias'];?></h4>
|
||||
<br />
|
||||
<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
|
||||
<input type="hidden" name="address" value="<?=htmlspecialchars($alias);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="goto"><?=$lang['edit']['target_address'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" autocapitalize="none" autocorrect="off" rows="10" id="goto" name="goto"><?=htmlspecialchars($result['goto']) ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<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_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="mailbox_edit_alias" 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
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['domainadmin']) &&
|
||||
ctype_alnum(str_replace(array('_', '.', '-'), '', $_GET["domainadmin"])) &&
|
||||
!empty($_GET["domainadmin"]) &&
|
||||
$_GET["domainadmin"] != 'admin' &&
|
||||
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$domain_admin = $_GET["domainadmin"];
|
||||
$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_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
|
||||
foreach ($result['selected_domains'] as $domain):
|
||||
?>
|
||||
<option selected><?=htmlspecialchars($domain);?></option>
|
||||
<?php
|
||||
endforeach;
|
||||
foreach ($result['unselected_domains'] as $domain):
|
||||
?>
|
||||
<option><?=htmlspecialchars($domain);?></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="">
|
||||
</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" <?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">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="disable_tfa"> <?=$lang['tfa']['disable_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>
|
||||
<?php
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['domain']) &&
|
||||
is_valid_domain_name($_GET["domain"]) &&
|
||||
!empty($_GET["domain"])) {
|
||||
$domain = $_GET["domain"];
|
||||
$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;?>">
|
||||
<input type="hidden" name="domain" value="<?=htmlspecialchars($domain);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="description"><?=$lang['edit']['description'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="description" id="description" value="<?=htmlspecialchars($result['description']);?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin") {
|
||||
?>
|
||||
<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['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['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['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['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" <?=(isset($result['backupmx_int']) && $result['backupmx_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_domain'];?></label>
|
||||
<br />
|
||||
<label><input type="checkbox" name="relay_all_recipients" <?=(isset($result['relay_all_recipients_int']) && $result['relay_all_recipients_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_all'];?></label>
|
||||
<p><?=$lang['edit']['relay_all_info'];?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<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_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="mailbox_edit_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
if (!empty($dkim = dkim_get_key_details($domain))) {
|
||||
?>
|
||||
<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 {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['aliasdomain']) &&
|
||||
is_valid_domain_name($_GET["aliasdomain"]) &&
|
||||
!empty($_GET["aliasdomain"])) {
|
||||
$alias_domain = $_GET["aliasdomain"];
|
||||
$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;?>">
|
||||
<input type="hidden" name="alias_domain_now" value="<?=htmlspecialchars($alias_domain);?>">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="alias_domain"><?=$lang['edit']['alias_domain'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="alias_domain" id="alias_domain" value="<?=htmlspecialchars($result['alias_domain']);?>">
|
||||
</div>
|
||||
</div>
|
||||
<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_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="mailbox_edit_alias_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
if (!empty($dkim = dkim_get_key_details($alias_domain))) {
|
||||
?>
|
||||
<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 {
|
||||
?>
|
||||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['mailbox']) && filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
||||
$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="name" value="<?=htmlspecialchars($result['name']);?>">
|
||||
<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" value="<?=htmlspecialchars($result['description'], ENT_QUOTES, 'UTF-8');?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['kind'];?>:</label>
|
||||
<div class="col-sm-10">
|
||||
<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">
|
||||
<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">
|
||||
<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="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">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="active" <?=($result['active']=="1") ? "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="edit_syncjob" value="1" 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
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<div class="alert alert-danger" role="alert"><?=$lang['danger']['access_denied'];?></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="<?=$_SESSION['return_to'];?>">← <?=$lang['edit']['previous'];?></a>
|
||||
</div> <!-- /container -->
|
||||
<?php
|
||||
require_once("inc/footer.inc.php");
|
||||
?>
|
BIN
data/web/favicon.png
Normal file
BIN
data/web/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
197
data/web/img/cow_mailcow.svg
Normal file
197
data/web/img/cow_mailcow.svg
Normal file
@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="446.22601"
|
||||
height="396.02499"
|
||||
viewBox="0 0 446.226 396.02499"
|
||||
enable-background="new 0 0 1600 1200"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="cow_mailcow.svg"><metadata
|
||||
id="metadata144"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs142" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1097"
|
||||
inkscape:window-height="1138"
|
||||
id="namedview140"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.1125147"
|
||||
inkscape:cx="261.00704"
|
||||
inkscape:cy="233.97883"
|
||||
inkscape:window-x="814"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" /><g
|
||||
id="g3"
|
||||
transform="translate(-576.88698,-401.988)"><g
|
||||
id="g5"><g
|
||||
id="g7"><g
|
||||
id="email"><path
|
||||
d="m 890.306,557.81 29.26,11.373 0,172.027 c 0,9.753 -7.895,17.649 -17.638,17.649 l -235.998,0 c -9.743,0 -17.638,-7.896 -17.638,-17.649 l 0,-172.026 29.259,-8.937"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#5a3620" /><path
|
||||
d="M 758.871,656.221 649.49,747.45 c 2.507,6.648 8.901,11.409 16.44,11.409 l 235.998,0 c 7.536,0 13.933,-4.761 16.444,-11.409 l -107.402,-91.229 -52.099,0 z"
|
||||
id="path12"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fee70f;fill-opacity:0.89499998" /><g
|
||||
id="g14"><path
|
||||
d="m 810.391,656.686 107.981,90.764 c -0.331,0.881 -0.744,1.726 -1.205,2.536 l 0.028,0.035 c 1.501,-2.596 2.371,-5.594 2.371,-8.81 l 0,-172.004 -109.175,87.479 z"
|
||||
id="path16"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f9e82d;fill-opacity:1" /><path
|
||||
d="m 649.49,747.45 108.864,-90.764 -110.061,-87.479 0,172.003 c 0,3.216 0.876,6.214 2.367,8.81 l 0.039,-0.035 c -0.466,-0.809 -0.877,-1.654 -1.209,-2.535 z"
|
||||
id="path18"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f9e82d;fill-opacity:1" /></g></g><path
|
||||
d="m 961.81,681.214 c 0,0 -15.232,16.783 -42.244,14.73 l 0,28.14 c 13.328,-5.185 47.061,-20.036 56.854,-40.809 l -14.61,-2.061 z"
|
||||
id="path20"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#b58765" /><path
|
||||
d="m 984.594,658.413 c 3.59,-9.156 7.701,-11 9.346,-11.346 -49.276,4.542 -32.99,38.693 -32.99,38.693 0,0 6.229,14.728 26.532,13.892 27.063,0.461 35.631,-50.166 35.631,-50.166 -6.654,11.655 -26.404,9.876 -38.519,8.927 z"
|
||||
id="path22"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fef3df" /><ellipse
|
||||
cx="787.75098"
|
||||
cy="788.54498"
|
||||
rx="210.864"
|
||||
ry="9.4680004"
|
||||
id="ellipse24"
|
||||
style="fill:#f1f2f2" /><path
|
||||
d="m 783.931,446.247 c -66.396,0 -120.223,53.827 -120.223,120.223 0,66.396 53.827,120.221 120.223,120.221 66.397,0 120.222,-53.825 120.222,-120.221 0,-66.395 -53.825,-120.223 -120.222,-120.223 z m -11.96,215.702 c -53.009,0 -95.982,-43.855 -95.982,-97.953 0,-54.098 42.973,-97.952 95.982,-97.952 53.007,0 95.98,43.855 95.98,97.952 -10e-4,54.098 -42.973,97.953 -95.98,97.953 z"
|
||||
id="path26"
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.1;fill:#3d5263" /><g
|
||||
id="g28"><g
|
||||
id="g30"><polyline
|
||||
points="691.144,492.5 673.257,540.276 686.55,605.582 712.496,631.852 "
|
||||
id="polyline32"
|
||||
style="fill:#3d5263" /><g
|
||||
id="g34"><g
|
||||
id="g36"><polyline
|
||||
points="658.248,450.81 673.501,487.076 693.836,496.903 724.04,458.731 "
|
||||
id="polyline38"
|
||||
style="fill:#fef3df" /><g
|
||||
id="g40"><path
|
||||
d="m 710.634,473.205 c 0,0 -22.482,-25.556 -49.793,-18.975 0,0 4.667,34.118 46.349,44.019 l 2.61,8.533 c 0,0 -65.612,-9.689 -59.339,-67.593 0,0 49.008,-19.884 72.598,15.106"
|
||||
id="path42"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#b58765" /><polyline
|
||||
points="909.697,450.81 894.447,487.076 874.114,496.903 843.907,458.731 "
|
||||
id="polyline44"
|
||||
style="fill:#fef3df" /><path
|
||||
d="m 857.314,473.205 c 0,0 22.48,-25.556 49.79,-18.975 0,0 -4.664,34.118 -46.347,44.019 l -2.613,8.533 c 0,0 65.611,-9.689 59.339,-67.593 0,0 -49.006,-19.884 -72.6,15.106"
|
||||
id="path46"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#b58765" /></g></g><path
|
||||
d="m 726.619,647.067 55.945,0 16.40428,-204.81407 c -55.814,0 -112.41728,30.01707 -112.41728,77.85207 0,1.454 0.085,2.787 0.121,4.175 0.127,3.934 0.448,7.585 0.856,11.135 1.689,14.816 5.451,27.177 8.461,43.383 1.452,7.831 5.002,23.374 5.002,23.374 0.056,0.408 0.165,0.804 0.224,1.211 2.535,16.546 11.832,32.027 25.404,43.684 z"
|
||||
id="path48"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#b58765"
|
||||
sodipodi:nodetypes="cccscccccc" /><path
|
||||
d="m 781.992,433.489 0,213.577 55.944,0 c 13.572,-11.657 22.867,-27.138 25.406,-43.684 0.058,-0.407 0.163,-0.803 0.221,-1.211 0,0 3.549,-15.543 5.002,-23.374 3.011,-16.206 6.774,-28.567 8.464,-43.381 0.405,-3.552 0.724,-7.203 0.846,-11.137 0.042,-1.388 0.126,-2.721 0.126,-4.175 0,-47.834 -40.191,-86.615 -96.009,-86.615 z"
|
||||
id="path50"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#b58765" /><g
|
||||
id="g52"><g
|
||||
id="g54"><path
|
||||
d="m 860.944,613.502 c 0,28.321 -35.091,51.289 -78.383,51.289 -43.299,0 -78.388,-22.968 -78.388,-51.289 0,-28.325 35.089,-51.289 78.388,-51.289 43.292,0 78.383,22.964 78.383,51.289 z"
|
||||
id="path56"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fef3df" /></g></g><g
|
||||
id="g58"><g
|
||||
id="g60"><g
|
||||
id="g62"><path
|
||||
d="m 747.044,605.582 c 0,6.215 -5.04,11.256 -11.261,11.256 -6.21,0 -11.253,-5.041 -11.253,-11.256 0,-6.223 5.043,-11.257 11.253,-11.257 6.22,0 11.261,5.034 11.261,11.257 z"
|
||||
id="path64"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#5a3620" /></g></g><g
|
||||
id="g66"><g
|
||||
id="g68"><path
|
||||
d="m 840.856,605.582 c 0,6.215 -5.037,11.256 -11.257,11.256 -6.218,0 -11.259,-5.041 -11.259,-11.256 0,-6.223 5.041,-11.257 11.259,-11.257 6.22,0 11.257,5.034 11.257,11.257 z"
|
||||
id="path70"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#5a3620" /></g></g></g><g
|
||||
id="g72"><path
|
||||
d="m 875.228,525.835 c 0.354,-3.113 0.634,-6.311 0.743,-9.754 0.035,-1.218 0.109,-2.384 0.109,-3.661 0,-40.785 -33.369,-74.043 -80.237,-75.775 l -7.335,0.005 c -0.003,0 -0.003,0 -0.006,0 -0.007,0.018 -28.632,88.422 76.583,140.268 0.946,-4.317 2.078,-9.585 2.73,-13.088 2.64,-14.196 5.934,-25.021 7.413,-37.995 z"
|
||||
id="path74"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#87654a" /></g><g
|
||||
id="g76"><g
|
||||
id="g78"><g
|
||||
id="g80"><g
|
||||
id="g82"><path
|
||||
d="m 843.907,519.681 c 0,6.964 -5.65,12.611 -12.618,12.611 -6.963,0 -12.614,-5.646 -12.614,-12.611 0,-6.97 5.651,-12.614 12.614,-12.614 6.968,0 12.618,5.644 12.618,12.614 z"
|
||||
id="path84"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#5a3620" /></g></g></g><g
|
||||
id="g86"><g
|
||||
id="g88"><g
|
||||
id="g90"><path
|
||||
d="m 752.028,519.681 c 0,6.964 -5.649,12.611 -12.612,12.611 -6.969,0 -12.612,-5.646 -12.612,-12.611 0,-6.97 5.642,-12.614 12.612,-12.614 6.964,0 12.612,5.644 12.612,12.614 z"
|
||||
id="path92"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#5a3620" /></g></g></g><g
|
||||
id="g94"><g
|
||||
id="g96"><path
|
||||
d="m 748.75,515.894 c 0,2.558 -2.071,4.629 -4.63,4.629 -2.558,0 -4.633,-2.072 -4.633,-4.629 0,-2.552 2.076,-4.626 4.633,-4.626 2.559,0 4.63,2.073 4.63,4.626 z"
|
||||
id="path98"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /></g></g><g
|
||||
id="g100"><g
|
||||
id="g102"><path
|
||||
d="m 839.771,515.894 c 0,2.558 -2.073,4.629 -4.629,4.629 -2.558,0 -4.631,-2.072 -4.631,-4.629 0,-2.552 2.072,-4.626 4.631,-4.626 2.555,0 4.629,2.073 4.629,4.626 z"
|
||||
id="path104"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /></g></g></g></g><path
|
||||
d="m 734.557,443.625 c 0,0 -18.236,-25.199 0,-41.637 0,0 13.125,32.012 40.242,31.502"
|
||||
id="path106"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fef3df" /><path
|
||||
d="m 834.496,443.625 c 0,0 18.236,-25.199 0,-41.637 0,0 -13.126,32.012 -40.242,31.502"
|
||||
id="path108"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fef3df" /><path
|
||||
d="m 786.264,431.965 c -66.396,0 -120.223,53.827 -120.223,120.223 0,66.396 53.827,120.221 120.223,120.221 66.397,0 120.222,-53.825 120.222,-120.221 10e-4,-66.395 -53.825,-120.223 -120.222,-120.223 z m -11.96,215.702 c -53.009,0 -95.982,-43.855 -95.982,-97.953 0,-54.098 42.973,-97.952 95.982,-97.952 53.007,0 95.979,43.855 95.979,97.952 0,54.098 -42.972,97.953 -95.979,97.953 z"
|
||||
id="path110"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f1f2f2" /></g><g
|
||||
id="g112"><path
|
||||
d="m 781.737,436.751 c 66.396,0 120.221,53.827 120.221,120.223 0,30.718 -11.526,58.74 -30.482,79.991 21.636,-21.74 35.01,-51.708 35.01,-84.803 0,-66.395 -53.825,-120.222 -120.222,-120.222 -35.678,0 -67.721,15.549 -89.739,40.233 21.772,-21.879 51.91,-35.422 85.212,-35.422 z"
|
||||
id="path114"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /></g></g><path
|
||||
d="m 919.566,695.944 c 0,0 7.562,0.712 13.317,-0.502 l 13.013,16.12 c 0,0 -17.639,9.525 -26.33,12.523 l 0,-28.141 z"
|
||||
id="path116"
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.1;fill:#3d5263" /></g><path
|
||||
d="m 648.292,659.614 0,81.645 c 0,9.72 7.88,17.6 17.6,17.6 l 236.073,0 c 9.72,0 17.6,-7.88 17.6,-17.6 l 0,-24.902 c 10e-4,0 -175.814,35.524 -271.273,-56.743 z"
|
||||
id="path124"
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.1;fill:#3d5263" /></g><g
|
||||
id="g126" /></g></svg>
|
After Width: | Height: | Size: 12 KiB |
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 |
225
data/web/inc/footer.inc.php
Normal file
225
data/web/inc/footer.inc.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?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">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title"><?=$lang['footer']['restart_sogo'];?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p><?=$lang['footer']['restart_sogo_info'];?></p>
|
||||
<hr />
|
||||
<button class="btn btn-md btn-primary" id="triggerRestartSogo"><?=$lang['footer']['restart_now'];?></button>
|
||||
<br /><br />
|
||||
<div id="statusTriggerRestartSogo"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?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="/js/bootstrap-switch.min.js"></script>
|
||||
<script src="/js/bootstrap-slider.min.js"></script>
|
||||
<script src="/js/bootstrap-select.min.js"></script>
|
||||
<script src="/js/u2f-api.js"></script>
|
||||
<script>
|
||||
// Select language and reopen active URL without POST
|
||||
function setLang(sel) {
|
||||
$.post( "<?=$_SERVER['REQUEST_URI'];?>", {lang: sel} );
|
||||
window.location.href = window.location.pathname + window.location.search;
|
||||
}
|
||||
|
||||
$(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');
|
||||
});
|
||||
|
||||
// Remember last navigation pill
|
||||
(function () {
|
||||
'use strict';
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var id = $(this).parents('[role="tablist"]').attr('id');
|
||||
var key = 'lastTag';
|
||||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
localStorage.setItem(key, $(e.target).attr('href'));
|
||||
});
|
||||
$('[role="tablist"]').each(function (idx, elem) {
|
||||
var id = $(elem).attr('id');
|
||||
var key = 'lastTag';
|
||||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
var lastTab = localStorage.getItem(key);
|
||||
if (lastTab) {
|
||||
$('[href="' + lastTab + '"]').tab('show');
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Disable submit after submitting form
|
||||
$('form').submit(function() {
|
||||
if ($('form button[type="submit"]').data('submitted') == '1') {
|
||||
return false;
|
||||
} else {
|
||||
$(this).find('button[type="submit"]').first().text('<?=$lang['footer']['loading'];?>');
|
||||
$('form button[type="submit"]').attr('data-submitted', '1');
|
||||
function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); };
|
||||
$(document).on("keydown", disableF5);
|
||||
}
|
||||
});
|
||||
|
||||
// IE fix to hide scrollbars when table body is empty
|
||||
$('tbody').filter(function (index) {
|
||||
return $(this).children().length < 1;
|
||||
}).remove();
|
||||
|
||||
// Init Bootstrap Selectpicker
|
||||
$('select').selectpicker();
|
||||
|
||||
// Trigger SOGo restart
|
||||
$('#triggerRestartSogo').click(function(){
|
||||
$(this).prop("disabled",true);
|
||||
$(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
|
||||
$('#statusTriggerRestartSogo').text('Stopping SOGo workers, this may take a while... ');
|
||||
$.ajax({
|
||||
method: 'get',
|
||||
url: 'call_sogo_ctrl.php',
|
||||
data: {
|
||||
'ajax': true,
|
||||
'ACTION': 'stop'
|
||||
},
|
||||
success: function(data) {
|
||||
$('#statusTriggerRestartSogo').append(data);
|
||||
$('#statusTriggerRestartSogo').append('<br />Starting SOGo... ');
|
||||
$.ajax({
|
||||
method: 'get',
|
||||
url: 'call_sogo_ctrl.php',
|
||||
data: {
|
||||
'ajax': true,
|
||||
'ACTION': 'start'
|
||||
},
|
||||
success: function(data) {
|
||||
$('#statusTriggerRestartSogo').append(data);
|
||||
$('#triggerRestartSogo').html('<span class="glyphicon glyphicon-ok"></span> ');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
if (isset($_SESSION['return'])):
|
||||
?>
|
||||
<div class="container">
|
||||
<div style="position:fixed;bottom:8px;right:25px;min-width:300px;max-width:350px;z-index:2000">
|
||||
<div <?=($_SESSION['return']['type'] == 'danger') ? null : 'id="alert-fade"'?> class="alert alert-<?=$_SESSION['return']['type'];?>" role="alert">
|
||||
<a href="#" class="close" data-dismiss="alert"> ×</a>
|
||||
<?=htmlspecialchars($_SESSION['return']['msg']);?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['return']);
|
||||
endif;
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
<?php $stmt = null; $pdo = null; ?>
|
4922
data/web/inc/functions.inc.php
Normal file
4922
data/web/inc/functions.inc.php
Normal file
File diff suppressed because it is too large
Load Diff
104
data/web/inc/header.inc.php
Normal file
104
data/web/inc/header.inc.php
Normal file
@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?= $_SESSION['mailcow_locale'] ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>mailcow UI</title>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js" integrity="sha384-XxcvoeNF5V0ZfksTnV+bejnCsJjOOIzN6UVwF85WBsAnU3zeYh5bloN+L4WLgeNE" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.6/<?=strtolower(trim($DEFAULT_THEME));?>/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
|
||||
<link rel="stylesheet" href="/css/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">
|
||||
</head>
|
||||
<body style="padding-top:70px">
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/"><img height="32" alt="mailcow-logo" style="margin-top:-5px;" src="/img/cow_mailcow.svg" /></a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<?php
|
||||
if (isset($_SESSION['mailcow_locale'])) {
|
||||
?>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="lang-sm lang-lbl" lang="<?=$_SESSION['mailcow_locale'];?>"></span><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'de') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "de"))) ?>"><span class="lang-xs lang-lbl-full" lang="de"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'en') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "en"))) ?>"><span class="lang-xs lang-lbl-full" lang="en"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'es') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "es"))) ?>"><span class="lang-xs lang-lbl-full" lang="es"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
||||
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
?>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><?=$lang['header']['mailcow_settings'];?><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<?php
|
||||
if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin") {
|
||||
?>
|
||||
<li <?=(preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? 'class="active"' : ''?>><a href="/admin.php"><?=$lang['header']['administration'];?></a></li>
|
||||
<?php
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") {
|
||||
?>
|
||||
<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'] != "admin") {
|
||||
?>
|
||||
<li <?=(preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? 'class="active"' : ''?>><a href="/user.php"><?=$lang['header']['user_settings'];?></a></li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin"):
|
||||
?>
|
||||
<li><a href data-toggle="modal" data-target="#RestartSOGo"><span style="font-size:12px" class="glyphicon glyphicon-refresh" aria-hidden="true"></span> <?=$lang['header']['restart_sogo'];?></a></li>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div><!--/.container-fluid -->
|
||||
</nav>
|
||||
<form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
|
281
data/web/inc/init.sql
Normal file
281
data/web/inc/init.sql
Normal file
@ -0,0 +1,281 @@
|
||||
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',
|
||||
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',
|
||||
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
|
||||
) 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,
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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,
|
||||
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;
|
||||
|
||||
CREATE VIEW grouped_mail_aliases (username, aliases) AS
|
||||
SELECT goto, IFNULL(GROUP_CONCAT(address SEPARATOR ' '), '') AS address FROM alias
|
||||
WHERE address!=goto
|
||||
AND active = '1'
|
||||
AND address NOT LIKE '@%'
|
||||
GROUP BY goto;
|
||||
|
||||
CREATE VIEW grouped_sender_acl (username, send_as) AS
|
||||
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as FROM sender_acl
|
||||
WHERE send_as NOT LIKE '@%'
|
||||
GROUP BY logged_in_as;
|
||||
|
||||
CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
|
||||
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
|
||||
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_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
|
||||
) 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,
|
||||
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,
|
||||
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_name character varying(255) NOT NULL,
|
||||
c_uid character varying(255) NOT NULL,
|
||||
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_location character varying(255),
|
||||
c_orgmail character varying(255),
|
||||
c_partmails TEXT,
|
||||
c_partstates TEXT,
|
||||
c_category character varying(255),
|
||||
c_sequence INTeger,
|
||||
c_component character varying(10) NOT NULL,
|
||||
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_name character varying(255) NOT NULL,
|
||||
c_givenname character varying(255),
|
||||
c_cn character varying(255),
|
||||
c_sn character varying(255),
|
||||
c_screenname character varying(255),
|
||||
c_l character varying(255),
|
||||
c_mail character varying(255),
|
||||
c_o character varying(255),
|
||||
c_ou character varying(255),
|
||||
c_telephonenumber character varying(255),
|
||||
c_categories character varying(255),
|
||||
c_component character varying(10) NOT NULL,
|
||||
CONSTRAINT sogo_quick_contact_pkey PRIMARY KEY (c_folder_id, c_name)
|
||||
) 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,
|
||||
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_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,
|
||||
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,
|
||||
PRIMARY KEY (c_uid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
INSERT INTO `admin` (username, password, superadmin, created, modified, active) SELECT 'admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1 WHERE NOT EXISTS (SELECT * FROM `admin`);
|
||||
DELETE FROM `domain_admins`;
|
||||
INSERT INTO `domain_admins` (username, domain, created, active) SELECT `username`, 'ALL', NOW(), 1 FROM `admin` WHERE superadmin='1' AND `username` NOT IN (SELECT `username` FROM `domain_admins`);
|
1
data/web/inc/languages.min.css
vendored
Normal file
1
data/web/inc/languages.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
data/web/inc/languages.png
Normal file
BIN
data/web/inc/languages.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user