mirror of
https://github.com/YunoHost/dynette.git
synced 2024-09-03 20:06:17 +02:00
Black
This commit is contained in:
parent
2c8179530f
commit
e1b0bcb0b0
3 changed files with 36 additions and 23 deletions
41
app.py
41
app.py
|
@ -9,7 +9,9 @@ from flask import Flask, jsonify, request
|
||||||
from flask_limiter import Limiter
|
from flask_limiter import Limiter
|
||||||
from flask_limiter.util import get_remote_address
|
from flask_limiter.util import get_remote_address
|
||||||
|
|
||||||
DOMAIN_REGEX = re.compile(r"^([a-z0-9]{1}([a-z0-9\-]*[a-z0-9])*)(\.[a-z0-9]{1}([a-z0-9\-]*[a-z0-9])*)*(\.[a-z]{1}([a-z0-9\-]*[a-z0-9])*)$")
|
DOMAIN_REGEX = re.compile(
|
||||||
|
r"^([a-z0-9]{1}([a-z0-9\-]*[a-z0-9])*)(\.[a-z0-9]{1}([a-z0-9\-]*[a-z0-9])*)*(\.[a-z]{1}([a-z0-9\-]*[a-z0-9])*)$"
|
||||||
|
)
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_file("config.yml", load=yaml.safe_load)
|
app.config.from_file("config.yml", load=yaml.safe_load)
|
||||||
|
@ -20,14 +22,20 @@ limiter = Limiter(
|
||||||
storage_uri="memory://",
|
storage_uri="memory://",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert os.path.isdir(app.config['DB_FOLDER']), "You should create the DB folder declared in the config"
|
assert os.path.isdir(
|
||||||
|
app.config["DB_FOLDER"]
|
||||||
|
), "You should create the DB folder declared in the config"
|
||||||
|
|
||||||
|
|
||||||
def _validate_domain(domain):
|
def _validate_domain(domain):
|
||||||
|
|
||||||
if not DOMAIN_REGEX.match(domain):
|
if not DOMAIN_REGEX.match(domain):
|
||||||
return {"error": f"This is not a valid domain: {domain}"}, 400
|
return {"error": f"This is not a valid domain: {domain}"}, 400
|
||||||
|
|
||||||
if len(domain.split(".")) != 3 or domain.split(".", 1)[-1] not in app.config["DOMAINS"]:
|
if (
|
||||||
|
len(domain.split(".")) != 3
|
||||||
|
or domain.split(".", 1)[-1] not in app.config["DOMAINS"]
|
||||||
|
):
|
||||||
return {"error": f"This subdomain is not handled by this dynette server."}, 400
|
return {"error": f"This subdomain is not handled by this dynette server."}, 400
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,19 +44,19 @@ def _is_available(domain):
|
||||||
return not os.path.exists(f"{app.config['DB_FOLDER']}/{domain}.key")
|
return not os.path.exists(f"{app.config['DB_FOLDER']}/{domain}.key")
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
def home():
|
def home():
|
||||||
return 'Wanna play the dynette?'
|
return "Wanna play the dynette?"
|
||||||
|
|
||||||
|
|
||||||
@app.route('/domains')
|
@app.route("/domains")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
def domains():
|
def domains():
|
||||||
return jsonify(app.config["DOMAINS"]), 200
|
return jsonify(app.config["DOMAINS"]), 200
|
||||||
|
|
||||||
|
|
||||||
@app.route('/test/<domain>')
|
@app.route("/test/<domain>")
|
||||||
@limiter.limit("3 per minute")
|
@limiter.limit("3 per minute")
|
||||||
def availability(domain):
|
def availability(domain):
|
||||||
|
|
||||||
|
@ -62,7 +70,7 @@ def availability(domain):
|
||||||
return {"error": f"Subdomain already taken: {domain}"}, 409
|
return {"error": f"Subdomain already taken: {domain}"}, 409
|
||||||
|
|
||||||
|
|
||||||
@app.route('/key/<key>', methods=['POST'])
|
@app.route("/key/<key>", methods=["POST"])
|
||||||
@limiter.limit("5 per hour")
|
@limiter.limit("5 per hour")
|
||||||
def register(key):
|
def register(key):
|
||||||
|
|
||||||
|
@ -97,10 +105,11 @@ def register(key):
|
||||||
return {"error": "Recovery password too long"}, 409
|
return {"error": "Recovery password too long"}, 409
|
||||||
|
|
||||||
r_init = recovery_password
|
r_init = recovery_password
|
||||||
recovery_password = bcrypt.hashpw(password=recovery_password.encode(), salt=bcrypt.gensalt(14))
|
recovery_password = bcrypt.hashpw(
|
||||||
|
password=recovery_password.encode(), salt=bcrypt.gensalt(14)
|
||||||
|
)
|
||||||
recovery_password = base64.b64encode(recovery_password).decode()
|
recovery_password = base64.b64encode(recovery_password).decode()
|
||||||
|
|
||||||
|
|
||||||
with open(f"{app.config['DB_FOLDER']}/{subdomain}.key", "w") as f:
|
with open(f"{app.config['DB_FOLDER']}/{subdomain}.key", "w") as f:
|
||||||
f.write(key)
|
f.write(key)
|
||||||
|
|
||||||
|
@ -110,7 +119,8 @@ def register(key):
|
||||||
|
|
||||||
return "OK", 201
|
return "OK", 201
|
||||||
|
|
||||||
@app.route('/domains/<subdomain>', methods=['DELETE'])
|
|
||||||
|
@app.route("/domains/<subdomain>", methods=["DELETE"])
|
||||||
@limiter.limit("5 per hour")
|
@limiter.limit("5 per hour")
|
||||||
def delete_using_recovery_password_or_key(subdomain):
|
def delete_using_recovery_password_or_key(subdomain):
|
||||||
|
|
||||||
|
@ -120,8 +130,9 @@ def delete_using_recovery_password_or_key(subdomain):
|
||||||
assert isinstance(data, dict)
|
assert isinstance(data, dict)
|
||||||
recovery_password = data.get("recovery_password")
|
recovery_password = data.get("recovery_password")
|
||||||
key = data.get("key")
|
key = data.get("key")
|
||||||
assert (recovery_password and isinstance(recovery_password, str)) \
|
assert (recovery_password and isinstance(recovery_password, str)) or (
|
||||||
or (key and isinstance(key, str))
|
key and isinstance(key, str)
|
||||||
|
)
|
||||||
if key:
|
if key:
|
||||||
key = base64.b64decode(key).decode()
|
key = base64.b64decode(key).decode()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -139,7 +150,9 @@ def delete_using_recovery_password_or_key(subdomain):
|
||||||
if not hmac.compare_digest(key, f.read()):
|
if not hmac.compare_digest(key, f.read()):
|
||||||
return "Access denied", 403
|
return "Access denied", 403
|
||||||
if recovery_password:
|
if recovery_password:
|
||||||
if not os.path.exists(f"{app.config['DB_FOLDER']}/{subdomain}.recovery_password"):
|
if not os.path.exists(
|
||||||
|
f"{app.config['DB_FOLDER']}/{subdomain}.recovery_password"
|
||||||
|
):
|
||||||
return "Access denied", 403
|
return "Access denied", 403
|
||||||
with open(f"{app.config['DB_FOLDER']}/{subdomain}.recovery_password") as f:
|
with open(f"{app.config['DB_FOLDER']}/{subdomain}.recovery_password") as f:
|
||||||
hashed = base64.b64decode(f.read())
|
hashed = base64.b64decode(f.read())
|
||||||
|
|
16
gunicorn.py
16
gunicorn.py
|
@ -1,11 +1,11 @@
|
||||||
command = '/var/www/dynette/venv/bin/gunicorn'
|
command = "/var/www/dynette/venv/bin/gunicorn"
|
||||||
pythonpath = '/var/www/dynette'
|
pythonpath = "/var/www/dynette"
|
||||||
workers = 4
|
workers = 4
|
||||||
user = 'dynette'
|
user = "dynette"
|
||||||
bind = 'unix:/var/www/dynette/sock'
|
bind = "unix:/var/www/dynette/sock"
|
||||||
pid = '/run/gunicorn/dynette-pid'
|
pid = "/run/gunicorn/dynette-pid"
|
||||||
errorlog = '/var/log/dynette/error.log'
|
errorlog = "/var/log/dynette/error.log"
|
||||||
accesslog = '/var/log/dynette/access.log'
|
accesslog = "/var/log/dynette/access.log"
|
||||||
access_log_format = '%({X-Real-IP}i)s %({X-Forwarded-For}i)s %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
access_log_format = '%({X-Real-IP}i)s %({X-Forwarded-For}i)s %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
||||||
loglevel = 'warning'
|
loglevel = "warning"
|
||||||
capture_output = True
|
capture_output = True
|
||||||
|
|
Loading…
Reference in a new issue