184 lines
6.2 KiB
Python
184 lines
6.2 KiB
Python
from flask import Flask, render_template, request, redirect, url_for, make_response
|
|
import bcrypt
|
|
import sqlite3
|
|
import configparser
|
|
import subprocess
|
|
import os
|
|
from waitress import serve
|
|
|
|
# Load from config.ini
|
|
|
|
config = configparser.ConfigParser()
|
|
config.read("../config.ini")
|
|
database = config.get("Account", "database")
|
|
runport = config.get("Account", "port")
|
|
|
|
# Status report
|
|
|
|
print("HectaMail Account Service is starting up...")
|
|
print("Your database is located at:", database)
|
|
|
|
def is_valid_input(input_string):
|
|
return re.match(allowed_pattern, input_string) is not None
|
|
|
|
app = Flask(__name__)
|
|
|
|
def change_email_password(username, password):
|
|
if password and is_valid_input(username):
|
|
try:
|
|
|
|
# Create a temporary file to escape the password
|
|
|
|
with open("../tmp/chnpassword.tmp", "w") as file:
|
|
file.write(password)
|
|
|
|
# Pass the file through a shell command
|
|
cmd = ["cat", "../tmp/chnpassword.tmp", "|", "maddy", "creds", "password", f"{username}@hectabit.org"]
|
|
|
|
# Run and determine the result of the shell command
|
|
result = subprocess.run(" ".join(cmd), shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
# Delete the temporary file
|
|
os.remove("../tmp/chnpassword.tmp")
|
|
|
|
|
|
# Check if command executed correctly
|
|
if result.returncode == 0:
|
|
# Command executed successfully
|
|
return True
|
|
else:
|
|
# Handle errors, log them, and return False
|
|
error_message = result.stderr.decode("utf-8")
|
|
print(f"Error creating email account: {error_message}")
|
|
return False
|
|
except Exception as e:
|
|
# Handle exceptions and return False
|
|
print(f"Error creating email account: {str(e)}")
|
|
return False
|
|
else:
|
|
# Something went very wrong if this function triggers
|
|
print(f"Injection Bypass! Very bad!")
|
|
return False
|
|
|
|
|
|
def fetch_hash_from_database(key):
|
|
conn = sqlite3.connect(database)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT value FROM passwords WHERE key = ?", (key,))
|
|
result = cursor.fetchone()
|
|
conn.close()
|
|
|
|
if result:
|
|
return result[0][7:] # Remove the first 7 characters
|
|
else:
|
|
return None
|
|
|
|
def verify_bcrypt(passphrase, hashed_password):
|
|
return bcrypt.checkpw(passphrase.encode('utf-8'), hashed_password.encode('utf-8'))
|
|
|
|
@app.route('/')
|
|
def index():
|
|
email = request.cookies.get('email')
|
|
if 'passwordhash' in request.cookies and request.cookies.get('passwordhash'):
|
|
return render_template('dashboard.html', user_email=email)
|
|
else:
|
|
return render_template('index.html')
|
|
|
|
@app.route('/loginapi', methods=['POST'])
|
|
def login():
|
|
key_to_fetch = request.form['email']
|
|
password_to_check = request.form['password']
|
|
|
|
passwordhash = fetch_hash_from_database(key_to_fetch)
|
|
|
|
if passwordhash:
|
|
is_password_valid = verify_bcrypt(password_to_check, passwordhash)
|
|
if is_password_valid:
|
|
response = make_response(redirect('/account'))
|
|
response.set_cookie('passwordhash', passwordhash)
|
|
response.set_cookie('email', request.form['email'])
|
|
return response
|
|
else:
|
|
return render_template('wrong.html')
|
|
else:
|
|
return render_template('wrong.html')
|
|
|
|
@app.route('/deleteapi', methods=['POST'])
|
|
def delete():
|
|
key_to_fetch = request.form['email']
|
|
verify_hash = request.form['hash']
|
|
|
|
passwordhash = fetch_hash_from_database(key_to_fetch)
|
|
|
|
if passwordhash:
|
|
if verify_hash == passwordhash:
|
|
cmd = ["echo", "y", "|", "maddy", "creds", "remove", key_to_fetch]
|
|
result = subprocess.run(" ".join(cmd), shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
if result.returncode == 0:
|
|
# Command executed successfully
|
|
response = make_response(redirect('/'))
|
|
response.set_cookie('passwordhash', '', expires=0)
|
|
response.set_cookie('email', '', expires=0)
|
|
return response
|
|
else:
|
|
# Handle errors, log them, and return False
|
|
error_message = result.stderr.decode("utf-8")
|
|
print(f"Error deleting email account: {error_message}")
|
|
return render_template('err.html')
|
|
|
|
else:
|
|
return render_template('wrong.html')
|
|
else:
|
|
return render_template('wrong.html')
|
|
|
|
@app.route('/deleteacct')
|
|
def deleteacct():
|
|
email = request.cookies.get('email')
|
|
passwordhash = request.cookies.get('passwordhash')
|
|
if 'passwordhash' in request.cookies and request.cookies.get('passwordhash'):
|
|
return render_template('confirm.html', user_email=email, password_hash=passwordhash)
|
|
else:
|
|
return redirect('/account')
|
|
|
|
@app.route('/logout')
|
|
def logout():
|
|
response = make_response(redirect('/'))
|
|
response.set_cookie('passwordhash', '', expires=0)
|
|
response.set_cookie('email', '', expires=0)
|
|
return response
|
|
|
|
@app.route('/changepass')
|
|
def changepass():
|
|
email = request.cookies.get('email')
|
|
passwordhash = request.cookies.get('passwordhash')
|
|
if 'passwordhash' in request.cookies and request.cookies.get('passwordhash'):
|
|
return render_template('changepass.html', user_email=email, password_hash=passwordhash)
|
|
else:
|
|
return redirect('/account')
|
|
|
|
@app.route('/changeapi', methods=['POST'])
|
|
def register():
|
|
# Get the form data
|
|
username = request.form.get('username')
|
|
verifyhash = request.form.get('passwordhash')
|
|
password = request.form.get('password')
|
|
|
|
passwordhash = fetch_hash_from_database(username)
|
|
|
|
if verifyhash == passwordhash:
|
|
# Attempt to change the password
|
|
if change_email_password(username, password):
|
|
# Password changed
|
|
response.set_cookie('passwordhash', '', expires=0)
|
|
response.set_cookie('email', '', expires=0)
|
|
return redirect('/account')
|
|
else:
|
|
# Backend error, potentially maddy
|
|
return render_template('err.html'), 500
|
|
else:
|
|
return render_template('wrong.html'), 400
|
|
|
|
if __name__ == '__main__':
|
|
serve(app, host='0.0.0.0', port=runport)
|