2024-08-16 15:40:49 +02:00
|
|
|
|
from configparser import ConfigParser
|
|
|
|
|
from email.message import EmailMessage
|
|
|
|
|
import random
|
|
|
|
|
import operator
|
|
|
|
|
from os.path import exists
|
|
|
|
|
from secrets import token_urlsafe
|
|
|
|
|
from smtplib import SMTP
|
|
|
|
|
from time import time
|
|
|
|
|
|
|
|
|
|
import flask
|
|
|
|
|
import sqlalchemy
|
|
|
|
|
import sqlalchemy.orm
|
|
|
|
|
|
|
|
|
|
CONFIG_PATH = "/etc/contact-form/config.ini"
|
|
|
|
|
OPERATORS = (
|
|
|
|
|
('+', operator.add),
|
|
|
|
|
('×', operator.mul),
|
|
|
|
|
('-', operator.sub),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
config = ConfigParser()
|
|
|
|
|
config.read(CONFIG_PATH)
|
|
|
|
|
app = flask.Flask(__name__)
|
|
|
|
|
Base = sqlalchemy.orm.declarative_base()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Captcha(Base):
|
|
|
|
|
__tablename__ = "captcha"
|
|
|
|
|
|
|
|
|
|
token = sqlalchemy.Column(sqlalchemy.String(90), primary_key=True)
|
|
|
|
|
answer = sqlalchemy.Column(sqlalchemy.String(3))
|
|
|
|
|
expiration = sqlalchemy.Column(sqlalchemy.Integer())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_session():
|
|
|
|
|
db_path = config.get("app", "db_path", fallback="")
|
|
|
|
|
engine = sqlalchemy.create_engine(f"sqlite:///{db_path}")
|
|
|
|
|
if not exists(db_path):
|
|
|
|
|
Base.metadata.create_all(engine)
|
|
|
|
|
session_factory = sqlalchemy.orm.sessionmaker(engine)
|
|
|
|
|
return session_factory()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clean_db(session):
|
|
|
|
|
session.query(Captcha).filter(Captcha.expiration < int(time())).delete()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_captacha():
|
|
|
|
|
session = get_session()
|
|
|
|
|
clean_db(session)
|
|
|
|
|
first_number = random.randrange(10)
|
|
|
|
|
second_number = random.randrange(10)
|
|
|
|
|
op_text, op_func = random.choice(OPERATORS)
|
2024-08-16 19:15:17 +02:00
|
|
|
|
if op_text == "-" and first_number < second_number:
|
|
|
|
|
first_number, second_number = second_number, first_number
|
2024-08-16 15:40:49 +02:00
|
|
|
|
result = op_func(first_number, second_number)
|
|
|
|
|
captcha = Captcha(
|
|
|
|
|
token=token_urlsafe(67),
|
|
|
|
|
answer=str(result),
|
|
|
|
|
expiration=int(time()) + config.getint("app", "captcha_timout", fallback=3600),
|
|
|
|
|
)
|
|
|
|
|
session.add(captcha)
|
|
|
|
|
session.commit()
|
|
|
|
|
return {
|
|
|
|
|
"first_number": first_number,
|
|
|
|
|
"second_number": second_number,
|
|
|
|
|
"op_text": op_text,
|
|
|
|
|
"token": captcha.token,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def validate_captcha(token, value):
|
|
|
|
|
result = False
|
|
|
|
|
session = get_session()
|
|
|
|
|
clean_db(session)
|
|
|
|
|
captcha = session.query(Captcha).filter(Captcha.token == token).one_or_none()
|
|
|
|
|
if captcha:
|
|
|
|
|
result = value == captcha.answer
|
|
|
|
|
session.query(Captcha).filter(Captcha.token == token).delete()
|
|
|
|
|
session.commit()
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def send_email(sender, message):
|
2024-08-16 19:15:17 +02:00
|
|
|
|
katzei_email = EmailMessage()
|
|
|
|
|
katzei_email.set_content(message)
|
|
|
|
|
katzei_email["From"] = sender
|
|
|
|
|
katzei_email["To"] = config.get("email", "reciever")
|
|
|
|
|
katzei_email["Subject"] = config.get("email", "subject")
|
|
|
|
|
|
|
|
|
|
contact_email = EmailMessage()
|
|
|
|
|
contact_email.set_content(message)
|
|
|
|
|
contact_email["From"] = config.get("email", "sender")
|
|
|
|
|
contact_email["To"] = sender
|
|
|
|
|
contact_email["Subject"] = config.get("email", "subject")
|
|
|
|
|
|
2024-08-16 15:40:49 +02:00
|
|
|
|
smtp = SMTP(config.get("email", "server"))
|
2024-08-16 19:15:17 +02:00
|
|
|
|
smtp.send_message(katzei_email)
|
|
|
|
|
smtp.send_message(contact_email)
|
2024-08-16 15:40:49 +02:00
|
|
|
|
smtp.quit()
|
|
|
|
|
|
2024-08-16 19:15:17 +02:00
|
|
|
|
|
2024-08-16 15:40:49 +02:00
|
|
|
|
@app.route(config.get("app", "path"), methods=["GET"])
|
|
|
|
|
def get_form(context=None):
|
|
|
|
|
context = (context or {}) | generate_captacha()
|
|
|
|
|
return flask.render_template("form.html", **context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route(config.get("app", "path"), methods=["POST"])
|
|
|
|
|
def validate_form():
|
|
|
|
|
form = flask.request.form
|
|
|
|
|
if not all(form.get(f, False) for f in ("email", "message", "captcha", "token")):
|
|
|
|
|
return "Erreur", 400
|
|
|
|
|
if not validate_captcha(form["token"], form["captcha"]):
|
|
|
|
|
context = dict(**form)
|
|
|
|
|
context["captcha_error"] = True
|
|
|
|
|
context.pop("captcha", None)
|
|
|
|
|
return get_form(context=context)
|
|
|
|
|
send_email(sender=form["email"], message=form["message"])
|
|
|
|
|
return flask.render_template("success.html")
|
2024-08-16 19:15:17 +02:00
|
|
|
|
|
|
|
|
|
application=app
|