diff --git a/README.md b/README.md index 5fe8dd0..28e1fc8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-![banner](Assets/BannerNginxPM2.png) +![banner](static/Assets/BannerNginxPM2.png)

NginxPM2

A simple, but yet efficient, way of managing all your Nginx Proxy Manager instances !

diff --git a/app.py b/app.py index 4b059ec..63d9bf9 100644 --- a/app.py +++ b/app.py @@ -1,12 +1,73 @@ -from flask import Flask +import flask +from routes.auth.login import * +from routes.auth.register import * +import os +from flask_jwt_extended import jwt_required, JWTManager, unset_jwt_cookies, get_jwt_identity, get_jwt +from datetime import timedelta, datetime, timezone -app = Flask(__name__) +APP = flask.Flask(__name__) +jwt = JWTManager(APP) +APP.config['JWT_TOKEN_LOCATION'] = ['cookies'] +APP.config['JWT_SECRET_KEY'] = 'your-secret-key' +APP.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(days=1) -@app.route('/') -def hello_world(): - return 'Hello World!' + +@APP.route('/login', methods=['POST', 'GET']) +def login(): + if os.path.exists('user_files/admin/admin.json'): + return log_in() + else: + return redirect(url_for('register'), code=301) + + +@APP.route('/register', methods=['GET', 'POST']) +def register(): + if os.path.exists('user_files/admin/admin.json'): + return 'You are already registered' + return redirect(url_for('index'), code=301) + else: + return register_user() + + +@APP.route('/', methods=['GET', 'POST']) +@jwt_required() +def index(): + return render_template('index.html', code=200) + + +@APP.route('/logout', methods=['POST']) +def logout(): + resp = flask.make_response(flask.redirect(flask.url_for('login'))) + unset_jwt_cookies(resp) + return resp + + +@jwt.unauthorized_loader +def my_invalid_token_callback(expired_token): + print("unauthorized_loader", expired_token) + return redirect(url_for('login')) + + +@APP.errorhandler(401) +def unauthorized_error(error): + return redirect(url_for('login')) + + +@APP.after_request +def refresh_expiring_jwts(response): + try: + exp_timestamp = get_jwt()["exp"] + now = datetime.now(timezone.utc) + target_timestamp = datetime.timestamp(now + timedelta(minutes=30)) + if target_timestamp > exp_timestamp: + access_token = create_access_token(identity=get_jwt_identity()) + set_access_cookies(response, access_token) + return response + except (RuntimeError, KeyError): + return response if __name__ == '__main__': - app.run() + APP.debug=False + APP.run() \ No newline at end of file diff --git a/routes/auth/login.py b/routes/auth/login.py new file mode 100644 index 0000000..6afc3f3 --- /dev/null +++ b/routes/auth/login.py @@ -0,0 +1,31 @@ +from flask import render_template, request, redirect, url_for, make_response, jsonify +import json, bcrypt +from flask_jwt_extended import create_access_token, set_access_cookies + + +def log_in(): + error = None + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + + encrypted_username, encrypted_email, encrypted_password = load_encrypted_creds('user_files/admin/admin.json') + + if (bcrypt.checkpw(username.encode('utf8'), encrypted_username) or bcrypt.checkpw(username.encode('utf8'), encrypted_email)) and bcrypt.checkpw(password.encode('utf8'), encrypted_password): + access_token = create_access_token(identity=username) + response = make_response(redirect(url_for('index'))) + set_access_cookies(response, access_token) + return response + else: + error = 'Invalid Credentials. Please try again.' + return render_template('login/login.html', error=error) + return render_template('login/login.html', error=error) + + +def load_encrypted_creds(file): + loaded_json = json.load(open(file)) + username = loaded_json["username"].encode('utf8') + email = loaded_json["email"].encode('utf8') + password = loaded_json["password"].encode('utf8') + return username, email, password + diff --git a/routes/auth/register.py b/routes/auth/register.py new file mode 100644 index 0000000..cb82330 --- /dev/null +++ b/routes/auth/register.py @@ -0,0 +1,53 @@ +from flask import render_template, request, redirect, url_for +import bcrypt, hashlib, requests + + +def register_user(): + error = None + if request.method == 'POST': + username = request.form['username'] + email = request.form['email'].lower() + password = request.form['password'] + confirm_password = request.form['confirm_password'] + if isFormEmpty(request.form): + error = 'Please fill all the fields' + return render_template('register/register.html', error=error) + + if password != confirm_password: + error = 'Passwords do not match' + else: + crypted_username, crypted_email, crypted_password = crypt_data(username, email, password) + get_gravatar_icon(email) + with open('user_files/admin/admin.json', 'w') as file: + file.write('{\n "username": "' + crypted_username.decode('utf-8') + '",\n "email": "' + crypted_email.decode('utf-8') + '",\n "password": "' + crypted_password.decode('utf-8') + '"\n}') + return redirect(url_for('login')) + return render_template('register/register.html', error=error) + + +def isFormEmpty(form): + for key in form: + if form[key] == "": + return True + return False + + +def crypt_data(username, email, password): + crypted_username = bcrypt.hashpw(username.encode('utf-8'), bcrypt.gensalt()) + crypted_email = bcrypt.hashpw(email.encode('utf-8'), bcrypt.gensalt()) + crypted_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) + return crypted_username, crypted_email, crypted_password + +def get_gravatar_icon(email): + code = hashlib.md5(email.strip().encode('utf8')).hexdigest() + mail_url = f"https://www.gravatar.com/avatar/{code}?size=2048" + img_data = requests.get(mail_url) + if img_data.status_code == 200: + with open('user_files/admin/admin_avatar.png', 'wb') as f: + f.write(img_data.content) + + else: + img_data = requests.get("http://www.gravatar.com/avatar/?d=mp").content + with open('user_files/admin/admin_avatar.png', 'wb') as f: + f.write(img_data) + + diff --git a/Assets/BannerNginxPM2.png b/static/Assets/BannerNginxPM2.png similarity index 100% rename from Assets/BannerNginxPM2.png rename to static/Assets/BannerNginxPM2.png diff --git a/Assets/LogoNginxPM2.png b/static/Assets/LogoNginxPM2.png similarity index 100% rename from Assets/LogoNginxPM2.png rename to static/Assets/LogoNginxPM2.png diff --git a/static/login/style.css b/static/login/style.css new file mode 100644 index 0000000..9b17577 --- /dev/null +++ b/static/login/style.css @@ -0,0 +1,27 @@ +body { + background-color: #1e2124; + color: #ffffff; + margin-top: 50px; +} + +.container { + background-color: #282b30; + border-radius: 5px; + padding: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + max-width: 400px; + margin: auto; +} + +.dark-container { + color: #333333; +} + +.banner img { + max-width: 100%; + height: auto; + max-height: 150px; +} +.error { + color: red; +} \ No newline at end of file diff --git a/static/register/style.css b/static/register/style.css new file mode 100644 index 0000000..9d0aeb6 --- /dev/null +++ b/static/register/style.css @@ -0,0 +1,28 @@ +body { + background-color: #1e2124; + color: #ffffff; + margin-top: 50px; +} +.container { + background-color: #282b30; + border-radius: 5px; + padding: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + max-width: 400px; + margin: auto; +} + +.banner img { + max-width: 100%; + height: auto; + max-height: 150px; +} + +.dark-container { + color: #333333; +} + + +.error { + color: red; +} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..24370de --- /dev/null +++ b/templates/index.html @@ -0,0 +1,43 @@ + + + + + + Page d'accueil + + + + + +
+

Bienvenue sur notre site

+

Ceci est une page d'accueil simple.

+ + +
+ + + + diff --git a/templates/login/login.html b/templates/login/login.html new file mode 100644 index 0000000..e7d5d51 --- /dev/null +++ b/templates/login/login.html @@ -0,0 +1,33 @@ + + + + + + Login Page + + + + +
+ +

Login

+
+
+
+ +
+
+ +
+ +
+ {% if error %} +

Error: {{ error }}

+ {% endif %} +
+

Not registered yet ? Register here

+
+ + diff --git a/templates/register/register.html b/templates/register/register.html new file mode 100644 index 0000000..4206bd8 --- /dev/null +++ b/templates/register/register.html @@ -0,0 +1,39 @@ + + + + + + Register Page + + + + +
+ +

Register

+
+
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ {% if error %} +

Error: {{ error }}

+ {% endif %} +
+

Already have an account ? Login here

+
+ +