feat: Add mariaDB backend
This commit is contained in:
parent
d8267200ac
commit
821a0c405c
38
README.md
38
README.md
@ -1 +1,39 @@
|
|||||||
# shakecities
|
# shakecities
|
||||||
|
|
||||||
|
```
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
main:
|
||||||
|
image: git.woodburn.au/nathanwoodburn/shakecities:latest
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
environment:
|
||||||
|
DB_HOST: db
|
||||||
|
DB_USER: main
|
||||||
|
DB_PASSWORD: your-db-password
|
||||||
|
DB_NAME: main
|
||||||
|
WORKERS: 2 # number of workers to run (should be 2 * number of cores)
|
||||||
|
|
||||||
|
sites:
|
||||||
|
image: git.woodburn.au/nathanwoodburn/shakecities-sites:latest
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
environment:
|
||||||
|
DB_HOST: db
|
||||||
|
DB_USER: main
|
||||||
|
DB_PASSWORD: your-db-password
|
||||||
|
DB_NAME: main
|
||||||
|
WORKERS: 2 # number of workers to run (should be 2 * number of cores)
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: linuxserver/mariadb:latest
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: your-root-password
|
||||||
|
MYSQL_DATABASE: main
|
||||||
|
MYSQL_USER: main
|
||||||
|
MYSQL_PASSWORD: your-db-password
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
```
|
54
accounts.py
54
accounts.py
@ -2,6 +2,7 @@ import os
|
|||||||
import dotenv
|
import dotenv
|
||||||
from passlib.hash import argon2
|
from passlib.hash import argon2
|
||||||
import json
|
import json
|
||||||
|
import db
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
local = os.getenv('LOCAL')
|
local = os.getenv('LOCAL')
|
||||||
@ -9,6 +10,15 @@ local = os.getenv('LOCAL')
|
|||||||
def hash_password(password):
|
def hash_password(password):
|
||||||
return argon2.using(rounds=16).hash(password)
|
return argon2.using(rounds=16).hash(password)
|
||||||
|
|
||||||
|
def convert_db_users(db_entry):
|
||||||
|
return {
|
||||||
|
'id': db_entry[0],
|
||||||
|
'email': db_entry[1],
|
||||||
|
'domain': db_entry[2],
|
||||||
|
'password': db_entry[3],
|
||||||
|
'tokens': db_entry[4].split(',')
|
||||||
|
}
|
||||||
|
|
||||||
# Verify a password against a hashed password
|
# Verify a password against a hashed password
|
||||||
def verify_password(password, hashed_password):
|
def verify_password(password, hashed_password):
|
||||||
return argon2.verify(password, hashed_password)
|
return argon2.verify(password, hashed_password)
|
||||||
@ -40,30 +50,28 @@ def create_user(email, domain, password):
|
|||||||
token = generate_cookie()
|
token = generate_cookie()
|
||||||
user['tokens'] = [token]
|
user['tokens'] = [token]
|
||||||
|
|
||||||
# If file doesn't exist, create it
|
# Check if user exists
|
||||||
if not os.path.isfile('users.json'):
|
if db.search_users(email) != []:
|
||||||
with open('users.json', 'w') as f:
|
return {'success': False, 'message': 'User already exists'}
|
||||||
json.dump([], f)
|
|
||||||
|
|
||||||
|
db.add_user(email, domain, hashed_password, token)
|
||||||
|
|
||||||
# Write to file
|
|
||||||
with open('users.json', 'r') as f:
|
|
||||||
users = json.load(f)
|
|
||||||
|
|
||||||
for u in users:
|
|
||||||
if u['email'] == email:
|
|
||||||
return {'success': False, 'message': 'Email already exists'}
|
|
||||||
|
|
||||||
users.append(user)
|
|
||||||
with open('users.json', 'w') as f:
|
|
||||||
json.dump(users, f)
|
|
||||||
return {'success': True, 'message': 'User created', 'token': token}
|
return {'success': True, 'message': 'User created', 'token': token}
|
||||||
|
|
||||||
def validate_token(token):
|
def validate_token(token):
|
||||||
with open('users.json', 'r') as f:
|
search = db.search_users_token(token)
|
||||||
users = json.load(f)
|
if search == []:
|
||||||
for user in users:
|
return False
|
||||||
if token in user['tokens']:
|
else:
|
||||||
return user
|
return convert_db_users(search[0])
|
||||||
return False
|
|
||||||
|
def logout(token):
|
||||||
|
# Remove token from user
|
||||||
|
user = validate_token(token)
|
||||||
|
if not user:
|
||||||
|
return {'success': False, 'message': 'Invalid token'}
|
||||||
|
user['tokens'].remove(token)
|
||||||
|
# Update user
|
||||||
|
db.update_tokens(user['id'], user['tokens'])
|
||||||
|
|
||||||
|
|
||||||
|
return {'success': True, 'message': 'Logged out'}
|
78
db.py
Normal file
78
db.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import mysql.connector
|
||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
|
||||||
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
|
# Database connection
|
||||||
|
dbargs = {
|
||||||
|
'host':os.getenv('DB_HOST'),
|
||||||
|
'user':os.getenv('DB_USER'),
|
||||||
|
'password':os.getenv('DB_PASSWORD'),
|
||||||
|
'database':os.getenv('DB_NAME')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check_tables():
|
||||||
|
connection = mysql.connector.connect(**dbargs)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
domain VARCHAR(255) NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
token VARCHAR(255) NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
def add_user(email,domain,password,token):
|
||||||
|
connection = mysql.connector.connect(**dbargs)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO users (email, domain, password, token)
|
||||||
|
VALUES (%s, %s, %s, %s)
|
||||||
|
""", (email, domain, password, token))
|
||||||
|
connection.commit()
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
def search_users(email):
|
||||||
|
connection = mysql.connector.connect(**dbargs)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT * FROM users WHERE email = %s
|
||||||
|
""", (email,))
|
||||||
|
users = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
return users
|
||||||
|
|
||||||
|
def search_users_token(token):
|
||||||
|
connection = mysql.connector.connect(**dbargs)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "SELECT * FROM users WHERE token LIKE %s"
|
||||||
|
cursor.execute(query, ('%' + token + '%',))
|
||||||
|
|
||||||
|
users = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
return users
|
||||||
|
|
||||||
|
def update_tokens(id,tokens):
|
||||||
|
tokens = ','.join(tokens)
|
||||||
|
connection = mysql.connector.connect(**dbargs)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
UPDATE users SET token = %s WHERE id = %s
|
||||||
|
""", (tokens, id))
|
||||||
|
connection.commit()
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
23
main.py
23
main.py
@ -7,17 +7,25 @@ import schedule
|
|||||||
import time
|
import time
|
||||||
from email_validator import validate_email, EmailNotValidError
|
from email_validator import validate_email, EmailNotValidError
|
||||||
import accounts
|
import accounts
|
||||||
|
import db
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
|
# Database connection
|
||||||
|
dbargs = {
|
||||||
|
'host':os.getenv('DB_HOST'),
|
||||||
|
'user':os.getenv('DB_USER'),
|
||||||
|
'password':os.getenv('DB_PASSWORD'),
|
||||||
|
'database':os.getenv('DB_NAME')
|
||||||
|
}
|
||||||
|
|
||||||
#Assets routes
|
#Assets routes
|
||||||
@app.route('/assets/<path:path>')
|
@app.route('/assets/<path:path>')
|
||||||
def assets(path):
|
def assets(path):
|
||||||
return send_from_directory('templates/assets', path)
|
return send_from_directory('templates/assets', path)
|
||||||
|
|
||||||
#! TODO make prettier
|
|
||||||
def error(message):
|
def error(message):
|
||||||
return jsonify({'success': False, 'message': message}), 400
|
return jsonify({'success': False, 'message': message}), 400
|
||||||
|
|
||||||
@ -56,6 +64,17 @@ def signup():
|
|||||||
except EmailNotValidError as e:
|
except EmailNotValidError as e:
|
||||||
return jsonify({'success': False, 'message': 'Invalid email'}), 400
|
return jsonify({'success': False, 'message': 'Invalid email'}), 400
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
token = request.cookies['token']
|
||||||
|
if not accounts.logout(token)['success']:
|
||||||
|
return error('Invalid token')
|
||||||
|
|
||||||
|
# Remove cookie
|
||||||
|
resp = make_response(redirect('/'))
|
||||||
|
resp.set_cookie('token', '', expires=0)
|
||||||
|
return resp
|
||||||
|
|
||||||
@app.route('/<path:path>')
|
@app.route('/<path:path>')
|
||||||
def catch_all(path):
|
def catch_all(path):
|
||||||
# If file exists, load it
|
# If file exists, load it
|
||||||
@ -73,5 +92,7 @@ def not_found(e):
|
|||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
db.check_tables()
|
||||||
app.run(debug=False, port=5000, host='0.0.0.0')
|
app.run(debug=False, port=5000, host='0.0.0.0')
|
@ -7,4 +7,5 @@ schedule
|
|||||||
email-validator
|
email-validator
|
||||||
py3dns
|
py3dns
|
||||||
passlib
|
passlib
|
||||||
argon2-cffi
|
argon2-cffi
|
||||||
|
mysql-connector-python
|
Loading…
Reference in New Issue
Block a user