2020-10-17 22:04:19 +02:00
|
|
|
|
from configparser import ConfigParser
|
2024-11-09 12:03:55 +01:00
|
|
|
|
import operator
|
|
|
|
|
from os.path import exists
|
|
|
|
|
import random
|
|
|
|
|
from secrets import token_urlsafe
|
|
|
|
|
from time import time
|
2020-10-17 22:04:19 +02:00
|
|
|
|
|
|
|
|
|
from flask import (
|
|
|
|
|
Flask,
|
|
|
|
|
request,
|
|
|
|
|
render_template,
|
|
|
|
|
Response,
|
|
|
|
|
)
|
2024-11-09 12:03:55 +01:00
|
|
|
|
import sqlalchemy
|
|
|
|
|
import sqlalchemy.orm
|
2020-10-17 22:04:19 +02:00
|
|
|
|
|
|
|
|
|
from nextcloudregister.lib import (
|
|
|
|
|
CONFIG_PATH,
|
|
|
|
|
NextcloudApi,
|
|
|
|
|
NextcloudApiCannotSendEmail,
|
|
|
|
|
NextcloudApiException,
|
|
|
|
|
NextcloudApiInvalidInputData,
|
|
|
|
|
NextcloudApiNoEmailPassword,
|
|
|
|
|
NextcloudApiPermissionDenied,
|
|
|
|
|
NextcloudApiUsernamealreadyExists,
|
|
|
|
|
NextcloudApiUnknownError,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
config = ConfigParser()
|
|
|
|
|
config.read(CONFIG_PATH)
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
base_uri = config.get("web", "base_uri", fallback="")
|
|
|
|
|
base_uri = base_uri + ("" if base_uri.endswith("/") else "/")
|
2024-11-09 12:03:55 +01:00
|
|
|
|
db_path = config.get("rules", "db_path", fallback="db.sqlite")
|
|
|
|
|
Base = sqlalchemy.orm.declarative_base()
|
2020-10-17 22:04:19 +02:00
|
|
|
|
|
2024-11-09 12:03:55 +01:00
|
|
|
|
OPERATORS = (
|
|
|
|
|
('+', operator.add),
|
|
|
|
|
('×', operator.mul),
|
|
|
|
|
('-', operator.sub),
|
|
|
|
|
)
|
2020-10-17 22:04:19 +02:00
|
|
|
|
|
2024-11-09 12:03:55 +01:00
|
|
|
|
|
|
|
|
|
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():
|
|
|
|
|
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)
|
|
|
|
|
if op_text == "-" and first_number < second_number:
|
|
|
|
|
first_number, second_number = second_number, first_number
|
|
|
|
|
result = op_func(first_number, second_number)
|
|
|
|
|
captcha = Captcha(
|
|
|
|
|
token=token_urlsafe(67),
|
|
|
|
|
answer=str(result),
|
|
|
|
|
expiration=int(time()) + config.getint("rules", "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
|
2020-10-17 22:04:19 +02:00
|
|
|
|
|
|
|
|
|
|
2024-11-09 12:03:55 +01:00
|
|
|
|
@app.route(base_uri, methods=["GET"])
|
2020-10-17 22:04:19 +02:00
|
|
|
|
def form_get(data=None, error=None, info=None, success=False):
|
|
|
|
|
context = {
|
|
|
|
|
"base_uri": base_uri,
|
|
|
|
|
"data": data or {},
|
|
|
|
|
"disable": success,
|
|
|
|
|
"error": error,
|
|
|
|
|
"eula": config.get("web", "eula", fallback=""),
|
|
|
|
|
"favicon": config.get("web", "favicon", fallback=""),
|
|
|
|
|
"info": info,
|
|
|
|
|
"instance_link": config.get("web", "instance_link", fallback=""),
|
|
|
|
|
"max_accounts": config.getint("rules", "max_accounts", fallback=0),
|
|
|
|
|
"org_link": config.get("web", "org_link", fallback=""),
|
|
|
|
|
"success": success,
|
|
|
|
|
}
|
|
|
|
|
context["mandatory_password"] = config.getboolean(
|
|
|
|
|
"rules",
|
|
|
|
|
"mandatory_password",
|
|
|
|
|
fallback=True,
|
|
|
|
|
)
|
|
|
|
|
context["mandatory_email"] = config.getboolean(
|
|
|
|
|
"rules",
|
|
|
|
|
"mandatory_email",
|
|
|
|
|
fallback=False,
|
|
|
|
|
)
|
|
|
|
|
count_accounts = 0
|
|
|
|
|
api = NextcloudApi()
|
|
|
|
|
try:
|
|
|
|
|
count_accounts = api.count_accounts()
|
|
|
|
|
except NextcloudApiException:
|
2024-11-09 12:03:55 +01:00
|
|
|
|
context["count_accounts"] = context["max_accounts"]
|
2020-10-17 22:04:19 +02:00
|
|
|
|
if count_accounts >= context["max_accounts"] and not success:
|
|
|
|
|
context["disable"] = True
|
|
|
|
|
context["error"] = (
|
2021-04-06 22:29:09 +02:00
|
|
|
|
"Tous les comptes disponibles sur cette instance ont deja été "
|
2020-10-17 22:04:19 +02:00
|
|
|
|
"distribués."
|
|
|
|
|
)
|
2024-11-09 12:03:55 +01:00
|
|
|
|
context["count_accounts"] = 0
|
2020-10-17 22:04:19 +02:00
|
|
|
|
else:
|
|
|
|
|
context["count_accounts"] = context["max_accounts"] - count_accounts
|
2024-11-09 12:03:55 +01:00
|
|
|
|
context |= generate_captacha()
|
2020-10-17 22:04:19 +02:00
|
|
|
|
return render_template("form.html", **context)
|
|
|
|
|
|
|
|
|
|
|
2024-11-09 12:03:55 +01:00
|
|
|
|
@app.route(base_uri, methods=["POST"])
|
2020-10-17 22:04:19 +02:00
|
|
|
|
def form_post():
|
|
|
|
|
mandatory_email = config.getboolean(
|
|
|
|
|
"rules",
|
|
|
|
|
"mandatory_email",
|
|
|
|
|
fallback=False,
|
|
|
|
|
)
|
|
|
|
|
mandatory_password = config.getboolean(
|
|
|
|
|
"rules",
|
|
|
|
|
"mandatory_password",
|
|
|
|
|
fallback=False,
|
|
|
|
|
)
|
2024-11-09 12:03:55 +01:00
|
|
|
|
# validate captcha
|
|
|
|
|
if not validate_captcha(token=request.form.get("token"), value=request.form.get("answer")):
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Le captcha est invalide."
|
|
|
|
|
)
|
|
|
|
|
|
2020-10-17 22:04:19 +02:00
|
|
|
|
# validate mandatory fields
|
|
|
|
|
if not request.form.get("username"):
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Un nom d'utilisateur est obligatoire pour vous inscrire."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if mandatory_email and not request.form.get("email"):
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Une adresse mail est obligatoire pour vous inscrire."
|
|
|
|
|
)
|
|
|
|
|
if mandatory_password and not request.form.get("password1"):
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Un mot de passe est obligatoire pour vous inscrire."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# validate password
|
|
|
|
|
if request.form.get("password1"):
|
|
|
|
|
password1 = request.form.get("password1")
|
|
|
|
|
password2 = request.form.get("password2")
|
|
|
|
|
if not password1 == password2:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Les mots de passe ne correspondent pas."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
api = NextcloudApi()
|
2024-11-09 12:03:55 +01:00
|
|
|
|
try:
|
|
|
|
|
if api.count_accounts() >= config.getint("rules", "max_accounts", fallback=0):
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Tous les comptes disponibles sur cette instance ont deja été distribués."
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiException:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error="Tous les comptes disponibles sur cette instance ont deja été distribués."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2020-10-17 22:04:19 +02:00
|
|
|
|
try:
|
|
|
|
|
api.create_account(
|
2021-04-06 22:29:09 +02:00
|
|
|
|
username=request.form.get("username", "").strip(),
|
2020-10-17 22:04:19 +02:00
|
|
|
|
password=request.form.get("password1"),
|
2021-04-06 22:29:09 +02:00
|
|
|
|
email=request.form.get("email", "").strip(),
|
2020-10-17 22:04:19 +02:00
|
|
|
|
)
|
|
|
|
|
except NextcloudApiCannotSendEmail:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
2021-04-06 22:29:09 +02:00
|
|
|
|
error="Impossible d'envoyer un email pour la création du compte."
|
2020-10-17 22:04:19 +02:00
|
|
|
|
)
|
|
|
|
|
except NextcloudApiInvalidInputData:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
|
|
|
|
"Erreur interne. Merci de contacter l'administrateur de "
|
|
|
|
|
"l'instance Nextcloud."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiNoEmailPassword:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
2021-04-06 22:29:09 +02:00
|
|
|
|
"Une adresse email ou un mot de passe sont obligatoires pour "
|
2020-10-17 22:04:19 +02:00
|
|
|
|
"créer un compte Nextcloud."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiPermissionDenied:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
|
|
|
|
"Erreur interne. Merci de contacter l'administrateur de "
|
|
|
|
|
"l'instance Nextcloud. (Permission denied)"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiUsernamealreadyExists:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
|
|
|
|
"Le nom d'utilisateur que vous avez choisi est déjà utilisé "
|
|
|
|
|
"sur cette instance Nextcloud."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiUnknownError as err:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=err.hint
|
|
|
|
|
)
|
|
|
|
|
except NextcloudApiException as err:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
|
|
|
|
"Erreur interne. Merci de contacter l'administrateur de "
|
|
|
|
|
"l'instance Nextcloud. (%s)" % err
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
|
|
|
|
return form_get(
|
|
|
|
|
data=request.form,
|
|
|
|
|
error=(
|
|
|
|
|
"Erreur interne. Merci de contacter l'administrateur de "
|
|
|
|
|
"l'instance Nextcloud."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
if config.get("web", "instance_link", fallback=""):
|
|
|
|
|
return form_get(
|
|
|
|
|
info=(
|
2021-04-06 22:29:09 +02:00
|
|
|
|
"L'inscription est un succès, vous allez maintenant être "
|
2020-10-17 22:04:19 +02:00
|
|
|
|
"redirigé vers votre instance Nextcloud."
|
|
|
|
|
),
|
|
|
|
|
success=True,
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
return form_get(
|
2021-04-06 22:29:09 +02:00
|
|
|
|
info="Vous êtes maintenant inscrit sur cette instance Nextcloud",
|
2020-10-17 22:04:19 +02:00
|
|
|
|
success=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route(base_uri + "style.css")
|
|
|
|
|
def style():
|
|
|
|
|
context = {
|
|
|
|
|
"color": config.get("web", "color")
|
|
|
|
|
}
|
|
|
|
|
css_content = render_template("style.css", **context)
|
|
|
|
|
return Response(css_content, mimetype="text/css")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
application = app
|