Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Now working auth method ! #1

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div align='center'>

![banner](Assets/BannerNginxPM2.png)
![banner](static/Assets/BannerNginxPM2.png)
<h1>NginxPM2</h1>
<p>A simple, but yet efficient, way of managing all your Nginx Proxy Manager instances !</p>

Expand Down
73 changes: 67 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
@@ -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()
31 changes: 31 additions & 0 deletions routes/auth/login.py
Original file line number Diff line number Diff line change
@@ -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

53 changes: 53 additions & 0 deletions routes/auth/register.py
Original file line number Diff line number Diff line change
@@ -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)


File renamed without changes
File renamed without changes
27 changes: 27 additions & 0 deletions static/login/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
28 changes: 28 additions & 0 deletions static/register/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
43 changes: 43 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page d'accueil</title>
<!-- Ajouter Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+Knujsl5+zr/2+AzmbPFEY1pck9Oi7qOB7w5BzWRwKtk81U" crossorigin="anonymous">
<style>
/* Styles personnalisés ici */
</style>
</head>
<body>
<div class="container">
<h1 class="mt-5">Bienvenue sur notre site</h1>
<p>Ceci est une page d'accueil simple.</p>
<!-- Bouton de déconnexion -->
<button id="btnLogout" class="btn btn-danger mt-3">Déconnexion</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-QFhL/tFfQaTZYZF/Q2vRTJPnC/tfG4S7ZcK/GK8fSYyZOd4yi7ujF0pDc5cW4kE1" crossorigin="anonymous"></script>
<script>
// Ajoutez votre code JavaScript personnalisé ici
document.getElementById("btnLogout").addEventListener("click", function() {
// Redirection vers la route de déconnexion
fetch('/logout', {
method: 'POST',
credentials: 'same-origin'
})
.then(response => {
if (response.ok) {
// Si la déconnexion réussit, redirigez l'utilisateur vers la page de connexion
window.location.href = '/login'; // Remplacez '/login' par l'URL de votre page de connexion
} else {
console.error('Erreur lors de la déconnexion');
}
})
.catch(error => {
console.error('Erreur lors de la déconnexion :', error);
});
});
</script>
</body>
</html>
33 changes: 33 additions & 0 deletions templates/login/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Page</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="static/login/style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="banner">
<img src="static/Assets/BannerNginxPM2.png" alt="Bannière">
</div>
<h2 class="text-center">Login</h2>
<br>
<form action="" method="post">
<div class="form-group">
<input type="text" class="form-control bg-dark text-white" placeholder="Username or email" name="username" value="{{ request.form.username }}">
</div>
<div class="form-group">
<input type="password" class="form-control bg-dark text-white" placeholder="Password" name="password" value="{{ request.form.password }}">
</div>
<button type="submit" class="btn btn-primary btn-block">Login</button>
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}</p>
{% endif %}
<hr>
<p class="text-center">Not registered yet ? <a href="{{ url_for('register') }}">Register here</a></p>
</div>
</body>
</html>
39 changes: 39 additions & 0 deletions templates/register/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register Page</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="static/register/style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="banner">
<img src="static/Assets/BannerNginxPM2.png" alt="Bannière">
</div>
<h2 class="text-center">Register</h2>
<br>
<form action="" method="post">
<div class="form-group">
<input type="text" class="form-control bg-dark text-white" placeholder="Username" name="username" value="{{ request.form.username }}">
</div>
<div class="form-group">
<input type="email" class="form-control bg-dark text-white" placeholder="Email" name="email" value="{{ request.form.email }}">
</div>
<div class="form-group">
<input type="password" class="form-control bg-dark text-white" placeholder="Password" name="password" value="{{ request.form.password }}">
</div>
<div class="form-group">
<input type="password" class="form-control bg-dark text-white" placeholder="Confirm Password" name="confirm_password" value="{{ request.form.confirm_password }}">
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}</p>
{% endif %}
<hr>
<p class="text-center">Already have an account ? <a href="{{ url_for('login') }}">Login here</a></p>
</div>
</body>
</html>