flask-website/flask/floritiweb/lib/forms/mailform.py
2025-05-15 21:05:28 +02:00

238 lines
6.9 KiB
Python

from .handle_params import HandleParams, timewindowcheck
from email.message import EmailMessage
from subprocess import Popen, PIPE
import sys
import datetime
from textwrap import TextWrapper
from io import StringIO
import os
aa = open('/web/etc/allowed.adress')
addresses = {}
for line in aa:
short, longname, mailAddress = line.split(";")
addresses[short] = (longname, mailAddress.strip())
try:
aa.close()
except AttributeError:
pass
class ValidationError(RuntimeError):
def __init__(self, message):
self.langs = { 'de': message, 'en': message }
def __str__(self):
return self.langs['de']
HandleParams.ValidationError = ValidationError
class MultiLangExc(ValidationError):
def __init__(self, **langs):
self.langs = langs
timewindowcheck.init_db()
def init(params, altfields, defaults, check_remote_ip='0.0.0.0'):
hp = HandleParams(altered_fields=altfields, params=params, defaults=defaults)
def render_text(field, **args):
value = field.value
attr = attributes_to_string(args)
return f'<input style="width:75%;" type="text" value="{value}" {attr}>'
def render_textfield(field,**args):
value = field.value
attr = attributes_to_string(args)
return f'<textarea style="width: 75%; min-height: 12em;" {attr}>{value}</textarea>'
def render_checkbox(field, **args):
attr = attributes_to_string(args)
return f'<input type="checkbox" {attr} >'
mandatory_text = { 'de': "obligatorisch", 'en': "mandatory" }
def render_local_time(field,**args):
return str(datetime.datetime.now())
def must_be_nonempty(field, value):
if value is None or len(value) == 0:
raise MultiLangExc(**mandatory_text)
return True
def must_be_nonempty_then_validate(inner_val, field, value):
if len(value) == 0:
raise MultiLangExc(**mandatory_text)
return inner_val(self, value)
def validate_honeypot_field(field,value):
if len(value):
raise ValidationError(
"Sie haben ein verstecktes Feld ausgefüllt"
"(Honigtopf für Spambots)"
)
return True
def pass_longname(field, name):
value = field.value
try:
longname = addresses[value][0]
except KeyError:
longname = "Non-existent Enterprises Ltd (will forward)"
value = "ub"
return longname + f"<input type='hidden' name='adr' value='{value}'>"
def check_is_within_last24h():
pass
bei_allen_feldern_mgl = {
"mandatory": {
"required": True,
"wrap_validate": must_be_nonempty_then_validate,
}
}
hp.add_field("realname", {
"render":render_text
},
**bei_allen_feldern_mgl
)
hp.add_field("subject", {
"render":render_text,
"required": True,
})
hp.add_field("name", {
"validate": validate_honeypot_field,
"render":render_text
},
)
hp.add_field("body", {
"render":render_textfield,
"required": True,
})
hp.add_field("mailadr", {
"render":render_text
})
hp.add_field("wohnort", {
"render":render_text
})
hp.add_field("adr", {
"render":pass_longname
})
def twc_error(which):
msgs = {
"not passed": {
"de": "Spamprüfung gescheitert: kein timewindowcheck-Wert übergeben",
"en": "Spam detection failed: No field 'timewindowcheck' passed"
},
"invalid": { "de": "Zeitstempel und Digest ungültig", "en": "Timestamp and digest invalid" },
"missing": { "de": "Zeitstempel oder IP-Adresse nicht ermittelbar", "en": "Timestamp or IP address not indicated" },
"overused": { "de": "Der Zeitstempel wurde zu häufig verwendet", "en": "The timestamp has been used too often" },
"outdated": { "de": "Die Formularabfrage ist zu alt. Bitte laden Sie die Seite neu.", "en": "Form request is too old. Please reload the page." },
"fast_as_spambot": { "de": "Sie sind so schnell wie ein Spambot (oder schneller). Bitte lassen Sie sich vor dem Senden etwas mehr Zeit.", "en": "You are as fast as a spambot (or faster). Please have a breath or two before sending." },
}
return MultiLangExc(**msgs[which])
hp.add_field(
'timewindowcheck',
timewindowcheck.signed_fresh_timestamp_check(check_remote_ip, twc_error)
)
hp.add_field("dsgvochecked", {
"render":render_checkbox,
"rendervalue":render_local_time,
"required": True,
"validate": must_be_nonempty
})
return hp
def process(hp):
form = {
"adr": "adr",
"subject": "subject",
"realname": "realname",
"body": "body",
"ort": "wohnort",
"mymail": "mailadr",
"dsgvo_ts": "dsgvochecked",
}
for k,v in form.items():
form[k] = hp.fields[v].rendervalue() or hp.fields[v].value
adresse_formular = addresses[ hp.fields["adr"].value ][1]
# Mail bzw. Request rausschicken
send_mail(form, adresse_formular)
return form
def attributes_to_string(args):
attrs = []
for key, value in args.items():
attrs.append(f'{key}="{value}"')
return " ".join(attrs)
def send_mail(data, adr):
_w = TextWrapper(width=67, subsequent_indent=" "*13)
def wrap(label, slot):
_w.initial_indent = label+" "*(11-len(label))+': '
return _w.wrap(data[slot])
form = {
"Adressat": "adr",
"Betreff": "subject",
"Inhalt": "body",
"Absender": "realname",
"Wohnort": "ort",
"Antwort an": "mymail",
"DSE z.k.g.": "dsgvo_ts"
}
with open('/tmp/data_test.txt', 'w') as outfile:
outfile.write(str(data))
userinput = list()
for label,slot in form.items():
userinput.append('\n'.join(wrap(label,slot)))
text = ('' if data['mymail'] else """
-----------------------------------------------------------------
Bitte nicht die REPLY-Funktion verwenden. Es wurde keine Absende-
adresse angegeben.
Dieser Hinweis kann geloescht werden.
-----------------------------------------------------------------
""") + "\n".join(userinput)
mail = EmailMessage()
mail['From'] = 'WWW-Formular <noreply@example.invalid'
#mail['From'] = data['mymail'] or 'WWW-Formular'
mail['To'] = adr
del mail['Subject']
mail['Subject'] = data['subject']
mail.add_header('Content-Type', 'text/plain;charset=utf-8')
mail.set_payload(text)
mail_string = str(mail)
sml = Popen(['/usr/sbin/sendmail', '-t', '-oi'], stdin=PIPE)
#err = sml.communicate(mail.as_bytes(policy=mail.policy.clone(linesep='\r\n')))
with open('/var/tmp/mail_string_encode.txt', 'w') as file:
print(mail_string, file=file)
err = sml.communicate(mail_string.encode('utf8'))