contact-form/webapp.py
2024-08-16 15:55:20 +02:00

110 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
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):
email = EmailMessage()
email.set_content(message)
email["From"] = sender
email["To"] = config.get("email", "reciever")
smtp = SMTP(config.get("email", "server"))
smtp.send_message(email)
smtp.quit()
@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")