Compare commits
2 Commits
b71d9e2ded
...
7e646d2ae9
Author | SHA1 | Date | |
---|---|---|---|
7e646d2ae9 | |||
f06d2e7219 |
@ -4,13 +4,16 @@ WORKDIR /usr/src/app
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
RUN apk add python3-dev build-base linux-headers pcre-dev
|
||||
RUN apk add python3-dev build-base linux-headers pcre-dev spamassassin
|
||||
RUN pip install uwsgi
|
||||
#spamassassin_client
|
||||
|
||||
ENV UID=0
|
||||
ENV MOUNT=/
|
||||
|
||||
COPY ./main.py ./
|
||||
# Since the package maintainer doesnt merge PR
|
||||
# https://github.com/petermat/spamassassin_client/pull/2
|
||||
COPY ./main.py ./spamassassin/spamassasin_client.py ./
|
||||
|
||||
# I juste wanted to change the socket owner but it turned out I needed to change thu uwsgi user
|
||||
#CMD uwsgi --exec-asap 'chown $UID:$UID /tmp/uwsgi/ ; mkdir -p $BASE_PATH && chown $UID:$UID $BASE_PATH' -s /tmp/uwsgi/uwsgi.sock --uid $UID --manage-script-name --mount /=server:app
|
||||
|
@ -14,6 +14,7 @@ import random, string # for tokens
|
||||
import html # for sanitization
|
||||
from bson.json_util import dumps
|
||||
import datetime # For email date
|
||||
from spamassasin_client import SpamAssassin
|
||||
|
||||
|
||||
##################################################### Bottle stuff ############################################
|
||||
@ -136,7 +137,10 @@ def submission ():
|
||||
content = re.sub(form_regex, r'{\1}', form['content']).format(**content_fields)
|
||||
|
||||
try:
|
||||
if not send_mail(from_address, form['mail'], subject, content):
|
||||
msg = build_mail(from_address, form['mail'], subject, content)
|
||||
if is_spam(msg):
|
||||
return resp(400, 'Votre message semble être du spam !')
|
||||
if not send_mail(form['mail'], msg):
|
||||
return resp(500, 'Le mail n’a pas pu être envoyé.')
|
||||
except smtplib.SMTPDataError as e:
|
||||
response.status = 500
|
||||
@ -178,8 +182,7 @@ def fill_fields(request, fields):
|
||||
raise MissingParameterException("Le champs {} est obligatoire".format(field))
|
||||
return fields
|
||||
|
||||
def send_mail (from_address, to, subject, content):
|
||||
"""Actually connect to smtp server, build a message object and send it as a mail"""
|
||||
def build_mail(from_address, to, subject, content):
|
||||
msg = EmailMessage()
|
||||
msg['From'] = smtp_server_sender
|
||||
msg.add_header('reply-to', from_address)
|
||||
@ -189,8 +192,16 @@ def send_mail (from_address, to, subject, content):
|
||||
msg.set_content(MIMEText(content, 'plain', "utf-8"))
|
||||
#or
|
||||
#msg.set_content(content)
|
||||
return msg
|
||||
|
||||
def is_spam(msg):
|
||||
assassin = SpamAssassin(msg.as_string().encode(), 'spamassassin')
|
||||
return assassin.is_spam()
|
||||
|
||||
def send_mail (to, msg):
|
||||
"""Actually connect to smtp server and send the mail"""
|
||||
if do_not_send:
|
||||
print('------------------------------------ Following message wont be sent ------------------------------------')
|
||||
print('-------------------------- Following message sent. But only to stdout ----------------------------------')
|
||||
print(msg.as_string())
|
||||
print('--------------------------------------------------------------------------------------------------------')
|
||||
return True
|
||||
|
2
server/spamassassin/readme
Normal file
2
server/spamassassin/readme
Normal file
@ -0,0 +1,2 @@
|
||||
Since the package maintainer doesnt merge PR
|
||||
https://github.com/petermat/spamassassin_client/pull/2
|
115
server/spamassassin/spamassasin_client.py
Normal file
115
server/spamassassin/spamassasin_client.py
Normal file
@ -0,0 +1,115 @@
|
||||
import socket, select, re, logging
|
||||
from io import BytesIO
|
||||
|
||||
divider_pattern = re.compile(br'^(.*?)\r?\n(.*?)\r?\n\r?\n', re.DOTALL)
|
||||
first_line_pattern = re.compile(br'^SPAMD/[^ ]+ 0 EX_OK$')
|
||||
|
||||
|
||||
class SpamAssassin(object):
|
||||
def __init__(self, message, host='127.0.0.1', port=783, timeout=20):
|
||||
self.score = None
|
||||
self.symbols = None
|
||||
|
||||
# Connecting
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.settimeout(timeout)
|
||||
client.connect((host, port))
|
||||
|
||||
# Sending
|
||||
client.sendall(self._build_message(message))
|
||||
client.shutdown(socket.SHUT_WR)
|
||||
|
||||
# Reading
|
||||
resfp = BytesIO()
|
||||
while True:
|
||||
ready = select.select([client], [], [], timeout)
|
||||
if ready[0] is None:
|
||||
# Kill with Timeout!
|
||||
logging.info('[SpamAssassin] - Timeout ({0}s)!'.format(str(timeout)))
|
||||
break
|
||||
|
||||
data = client.recv(4096)
|
||||
if data == b'':
|
||||
break
|
||||
|
||||
resfp.write(data)
|
||||
|
||||
# Closing
|
||||
client.close()
|
||||
client = None
|
||||
|
||||
self._parse_response(resfp.getvalue())
|
||||
|
||||
def _build_message(self, message):
|
||||
reqfp = BytesIO()
|
||||
data_len = str(len(message)).encode()
|
||||
reqfp.write(b'REPORT SPAMC/1.2\r\n')
|
||||
reqfp.write(b'Content-Length: ' + data_len + b'\r\n')
|
||||
reqfp.write(b'User: cx42\r\n\r\n')
|
||||
reqfp.write(message)
|
||||
return reqfp.getvalue()
|
||||
|
||||
def _parse_response(self, response):
|
||||
if response == b'':
|
||||
logging.info("[SPAM ASSASSIN] Empty response")
|
||||
return None
|
||||
|
||||
match = divider_pattern.match(response)
|
||||
if not match:
|
||||
logging.error("[SPAM ASSASSIN] Response error:")
|
||||
logging.error(response)
|
||||
return None
|
||||
|
||||
first_line = match.group(1)
|
||||
headers = match.group(2)
|
||||
body = response[match.end(0):]
|
||||
|
||||
# Checking response is good
|
||||
match = first_line_pattern.match(first_line)
|
||||
if not match:
|
||||
logging.error("[SPAM ASSASSIN] invalid response:")
|
||||
logging.error(first_line)
|
||||
return None
|
||||
|
||||
report_list = [s.strip() for s in body.decode('utf-8').strip().split('\n')]
|
||||
linebreak_num = report_list.index([s for s in report_list if "---" in s][0])
|
||||
tablelists = [s for s in report_list[linebreak_num + 1:]]
|
||||
|
||||
self.report_fulltext = '\n'.join(report_list)
|
||||
|
||||
|
||||
# join line when current one is only wrap of previous
|
||||
tablelists_temp = []
|
||||
if tablelists:
|
||||
for counter, tablelist in enumerate(tablelists):
|
||||
if len(tablelist)>1:
|
||||
if (tablelist[0].isnumeric() or tablelist[0] == '-') and (tablelist[1].isnumeric() or tablelist[1] == '.'):
|
||||
tablelists_temp.append(tablelist)
|
||||
else:
|
||||
if tablelists_temp:
|
||||
tablelists_temp[-1] += " " + tablelist
|
||||
tablelists = tablelists_temp
|
||||
|
||||
# create final json
|
||||
self.report_json = dict()
|
||||
for tablelist in tablelists:
|
||||
wordlist = re.split('\s+', tablelist)
|
||||
self.report_json[wordlist[1]] = {'partscore': float(wordlist[0]), 'description': ' '.join(wordlist[1:])}
|
||||
|
||||
headers = headers.decode('utf-8').replace(' ', '').replace(':', ';').replace('/', ';').split(';')
|
||||
self.score = float(headers[2])
|
||||
|
||||
def get_report_json(self):
|
||||
return self.report_json
|
||||
|
||||
def get_score(self):
|
||||
return self.score
|
||||
|
||||
def is_spam(self, level=5):
|
||||
return self.score is None or self.score > level
|
||||
|
||||
def get_fulltext(self):
|
||||
return self.report_fulltext
|
||||
|
||||
|
||||
|
383
server/spamassassin/spamassassin_client
Normal file
383
server/spamassassin/spamassassin_client
Normal file
@ -0,0 +1,383 @@
|
||||
%!PS-Adobe-3.0
|
||||
%%Creator: (ImageMagick)
|
||||
%%Title: (spamassassin_client)
|
||||
%%CreationDate: (2021-05-17T23:08:26+00:00)
|
||||
%%BoundingBox: 428 345 508 391
|
||||
%%HiResBoundingBox: 428 345 508 391
|
||||
%%DocumentData: Clean7Bit
|
||||
%%LanguageLevel: 1
|
||||
%%Orientation: Portrait
|
||||
%%PageOrder: Ascend
|
||||
%%Pages: 1
|
||||
%%EndComments
|
||||
|
||||
%%BeginDefaults
|
||||
%%EndDefaults
|
||||
|
||||
%%BeginProlog
|
||||
%
|
||||
% Display a color image. The image is displayed in color on
|
||||
% Postscript viewers or printers that support color, otherwise
|
||||
% it is displayed as grayscale.
|
||||
%
|
||||
/DirectClassPacket
|
||||
{
|
||||
%
|
||||
% Get a DirectClass packet.
|
||||
%
|
||||
% Parameters:
|
||||
% red.
|
||||
% green.
|
||||
% blue.
|
||||
% length: number of pixels minus one of this color (optional).
|
||||
%
|
||||
currentfile color_packet readhexstring pop pop
|
||||
compression 0 eq
|
||||
{
|
||||
/number_pixels 3 def
|
||||
}
|
||||
{
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/number_pixels exch 1 add 3 mul def
|
||||
} ifelse
|
||||
0 3 number_pixels 1 sub
|
||||
{
|
||||
pixels exch color_packet putinterval
|
||||
} for
|
||||
pixels 0 number_pixels getinterval
|
||||
} bind def
|
||||
|
||||
/DirectClassImage
|
||||
{
|
||||
%
|
||||
% Display a DirectClass image.
|
||||
%
|
||||
systemdict /colorimage known
|
||||
{
|
||||
columns rows 8
|
||||
[
|
||||
columns 0 0
|
||||
rows neg 0 rows
|
||||
]
|
||||
{ DirectClassPacket } false 3 colorimage
|
||||
}
|
||||
{
|
||||
%
|
||||
% No colorimage operator; convert to grayscale.
|
||||
%
|
||||
columns rows 8
|
||||
[
|
||||
columns 0 0
|
||||
rows neg 0 rows
|
||||
]
|
||||
{ GrayDirectClassPacket } image
|
||||
} ifelse
|
||||
} bind def
|
||||
|
||||
/GrayDirectClassPacket
|
||||
{
|
||||
%
|
||||
% Get a DirectClass packet; convert to grayscale.
|
||||
%
|
||||
% Parameters:
|
||||
% red
|
||||
% green
|
||||
% blue
|
||||
% length: number of pixels minus one of this color (optional).
|
||||
%
|
||||
currentfile color_packet readhexstring pop pop
|
||||
color_packet 0 get 0.299 mul
|
||||
color_packet 1 get 0.587 mul add
|
||||
color_packet 2 get 0.114 mul add
|
||||
cvi
|
||||
/gray_packet exch def
|
||||
compression 0 eq
|
||||
{
|
||||
/number_pixels 1 def
|
||||
}
|
||||
{
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/number_pixels exch 1 add def
|
||||
} ifelse
|
||||
0 1 number_pixels 1 sub
|
||||
{
|
||||
pixels exch gray_packet put
|
||||
} for
|
||||
pixels 0 number_pixels getinterval
|
||||
} bind def
|
||||
|
||||
/GrayPseudoClassPacket
|
||||
{
|
||||
%
|
||||
% Get a PseudoClass packet; convert to grayscale.
|
||||
%
|
||||
% Parameters:
|
||||
% index: index into the colormap.
|
||||
% length: number of pixels minus one of this color (optional).
|
||||
%
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/offset exch 3 mul def
|
||||
/color_packet colormap offset 3 getinterval def
|
||||
color_packet 0 get 0.299 mul
|
||||
color_packet 1 get 0.587 mul add
|
||||
color_packet 2 get 0.114 mul add
|
||||
cvi
|
||||
/gray_packet exch def
|
||||
compression 0 eq
|
||||
{
|
||||
/number_pixels 1 def
|
||||
}
|
||||
{
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/number_pixels exch 1 add def
|
||||
} ifelse
|
||||
0 1 number_pixels 1 sub
|
||||
{
|
||||
pixels exch gray_packet put
|
||||
} for
|
||||
pixels 0 number_pixels getinterval
|
||||
} bind def
|
||||
|
||||
/PseudoClassPacket
|
||||
{
|
||||
%
|
||||
% Get a PseudoClass packet.
|
||||
%
|
||||
% Parameters:
|
||||
% index: index into the colormap.
|
||||
% length: number of pixels minus one of this color (optional).
|
||||
%
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/offset exch 3 mul def
|
||||
/color_packet colormap offset 3 getinterval def
|
||||
compression 0 eq
|
||||
{
|
||||
/number_pixels 3 def
|
||||
}
|
||||
{
|
||||
currentfile byte readhexstring pop 0 get
|
||||
/number_pixels exch 1 add 3 mul def
|
||||
} ifelse
|
||||
0 3 number_pixels 1 sub
|
||||
{
|
||||
pixels exch color_packet putinterval
|
||||
} for
|
||||
pixels 0 number_pixels getinterval
|
||||
} bind def
|
||||
|
||||
/PseudoClassImage
|
||||
{
|
||||
%
|
||||
% Display a PseudoClass image.
|
||||
%
|
||||
% Parameters:
|
||||
% class: 0-PseudoClass or 1-Grayscale.
|
||||
%
|
||||
currentfile buffer readline pop
|
||||
token pop /class exch def pop
|
||||
class 0 gt
|
||||
{
|
||||
currentfile buffer readline pop
|
||||
token pop /depth exch def pop
|
||||
/grays columns 8 add depth sub depth mul 8 idiv string def
|
||||
columns rows depth
|
||||
[
|
||||
columns 0 0
|
||||
rows neg 0 rows
|
||||
]
|
||||
{ currentfile grays readhexstring pop } image
|
||||
}
|
||||
{
|
||||
%
|
||||
% Parameters:
|
||||
% colors: number of colors in the colormap.
|
||||
% colormap: red, green, blue color packets.
|
||||
%
|
||||
currentfile buffer readline pop
|
||||
token pop /colors exch def pop
|
||||
/colors colors 3 mul def
|
||||
/colormap colors string def
|
||||
currentfile colormap readhexstring pop pop
|
||||
systemdict /colorimage known
|
||||
{
|
||||
columns rows 8
|
||||
[
|
||||
columns 0 0
|
||||
rows neg 0 rows
|
||||
]
|
||||
{ PseudoClassPacket } false 3 colorimage
|
||||
}
|
||||
{
|
||||
%
|
||||
% No colorimage operator; convert to grayscale.
|
||||
%
|
||||
columns rows 8
|
||||
[
|
||||
columns 0 0
|
||||
rows neg 0 rows
|
||||
]
|
||||
{ GrayPseudoClassPacket } image
|
||||
} ifelse
|
||||
} ifelse
|
||||
} bind def
|
||||
|
||||
/DisplayImage
|
||||
{
|
||||
%
|
||||
% Display a DirectClass or PseudoClass image.
|
||||
%
|
||||
% Parameters:
|
||||
% x & y translation.
|
||||
% x & y scale.
|
||||
% label pointsize.
|
||||
% image label.
|
||||
% image columns & rows.
|
||||
% class: 0-DirectClass or 1-PseudoClass.
|
||||
% compression: 0-none or 1-RunlengthEncoded.
|
||||
% hex color packets.
|
||||
%
|
||||
gsave
|
||||
/buffer 512 string def
|
||||
/byte 1 string def
|
||||
/color_packet 3 string def
|
||||
/pixels 768 string def
|
||||
|
||||
currentfile buffer readline pop
|
||||
token pop /x exch def
|
||||
token pop /y exch def pop
|
||||
x y translate
|
||||
currentfile buffer readline pop
|
||||
token pop /x exch def
|
||||
token pop /y exch def pop
|
||||
currentfile buffer readline pop
|
||||
token pop /pointsize exch def pop
|
||||
x y scale
|
||||
currentfile buffer readline pop
|
||||
token pop /columns exch def
|
||||
token pop /rows exch def pop
|
||||
currentfile buffer readline pop
|
||||
token pop /class exch def pop
|
||||
currentfile buffer readline pop
|
||||
token pop /compression exch def pop
|
||||
class 0 gt { PseudoClassImage } { DirectClassImage } ifelse
|
||||
grestore
|
||||
showpage
|
||||
} bind def
|
||||
%%EndProlog
|
||||
%%Page: 1 1
|
||||
%%PageBoundingBox: 428 345 508 391
|
||||
DisplayImage
|
||||
428 345
|
||||
80 46
|
||||
12
|
||||
80 46
|
||||
1
|
||||
1
|
||||
1
|
||||
8
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C
|
||||
1C1C1C1C1C1C1C1C
|
||||
%%PageTrailer
|
||||
%%Trailer
|
||||
%%EOF
|
@ -10,6 +10,7 @@ services:
|
||||
- ./uwsgi:/tmp/uwsgi
|
||||
depends_on:
|
||||
- db
|
||||
- spamassassin
|
||||
environment:
|
||||
MONGODB_HOST: db
|
||||
SMTP_SERVER_ADDRESS: toto.mail
|
||||
@ -36,3 +37,7 @@ services:
|
||||
nginx_uid: 1000
|
||||
depends_on:
|
||||
- mailer
|
||||
|
||||
spamassassin:
|
||||
image: dinkel/spamassassin
|
||||
restart: unless-stopped
|
||||
|
Loading…
Reference in New Issue
Block a user