hnshosting-wp/master/main.py

866 lines
28 KiB
Python
Raw Permalink Normal View History

2023-08-25 23:26:44 +10:00
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory
2023-08-16 13:47:49 +10:00
import dotenv
import os
2023-08-16 16:59:57 +10:00
import requests
2023-08-24 16:53:39 +10:00
import stripe # For stripe payments
import smtplib, ssl # For sending emails
2023-08-16 13:47:49 +10:00
dotenv.load_dotenv()
app = Flask(__name__)
2023-08-25 16:36:53 +10:00
logins = []
2023-08-25 16:29:25 +10:00
2023-08-16 13:47:49 +10:00
# API add license key (requires API key in header)
@app.route('/add-licence', methods=['POST'])
def add_license():
# Get API header
api_key = request.headers.get('key')
2023-08-25 16:29:25 +10:00
if api_key != os.getenv('LICENCE_KEY'):
2023-08-16 13:47:49 +10:00
return jsonify({'error': 'Invalid API key', 'success': 'false'})
# Generate licence key
licence_key = os.urandom(16).hex()
# Add license key to file
key_file = open('/data/licence_key.txt', 'a')
2023-08-16 13:47:49 +10:00
key_file.write(licence_key + '\n')
key_file.close()
return jsonify({'success': "true", 'licence_key': licence_key})
@app.route('/new-site', methods=['POST'])
def new_site():
domain=request.args.get('domain')
# Get API header
api_key = request.headers.get('key')
# Verify both API key and domain exist
if api_key == None:
2023-08-25 14:20:58 +10:00
return jsonify({'error': 'No licence provided', 'success': 'false'})
if domain == None:
return jsonify({'error': 'Missing domain', 'success': 'false'})
2023-08-16 13:47:49 +10:00
# Check if API key is a valid site key
key_file = open('/data/licence_key.txt', 'r')
valid_key = False
for line in key_file.readlines():
if api_key == line.strip('\n'):
valid_key = True
break
key_file.close()
if not valid_key:
return jsonify({'error': 'Invalid licence', 'success': 'false'})
2023-08-16 13:47:49 +10:00
# Check if domain already exists
if site_exists(domain):
return jsonify({'error': 'Domain already exists', 'success': 'false'})
2023-08-16 16:59:57 +10:00
# Check if domain contains http:// or https://
if domain.startswith("http://") or domain.startswith("https://"):
return jsonify({'error': 'Domain should not contain http:// or https://', 'success': 'false'})
# Check if worker file exists
workers = None
try:
worker_file = open('/data/workers.txt', 'r')
2023-08-16 16:59:57 +10:00
workers = worker_file.readlines()
worker_file.close()
except FileNotFoundError:
return jsonify({'error': 'No workers available', 'success': 'false'})
# Get a worker that has available slots
worker = None
for line in workers:
if not line.__contains__(':'):
continue
2023-08-16 16:59:57 +10:00
ip = line.split(':')[1].strip('\n')
resp=requests.get("http://"+ip + ":5000/status",timeout=2)
if (resp.status_code == 200):
if resp.json()['availability'] == True:
worker = line
break
if worker == None:
return jsonify({'error': 'No workers available', 'success': 'false'})
2023-08-16 13:47:49 +10:00
# Add domain to file
sites_file = open('/data/sites.txt', 'a')
2023-08-16 16:59:57 +10:00
sites_file.write(domain + ':' + worker.split(':')[0] + '\n')
2023-08-16 13:47:49 +10:00
sites_file.close()
# Use key
key_file = open('/data/licence_key.txt', 'r')
2023-08-16 13:47:49 +10:00
lines = key_file.readlines()
key_file.close()
key_file = open('/data/licence_key.txt', 'w')
2023-08-16 13:47:49 +10:00
for line in lines:
if line.strip("\n") != api_key:
key_file.write(line)
key_file.close()
2023-08-16 16:59:57 +10:00
# Send worker request
requests.post("http://"+ worker.split(':')[1].strip('\n') + ":5000/new-site?domain=" + domain)
2023-08-16 13:47:49 +10:00
return jsonify({'success': 'true', 'domain': domain, 'status': "creating"})
# Add worker
@app.route('/add-worker', methods=['POST'])
def add_worker():
worker=request.args.get('worker')
2023-08-16 16:59:57 +10:00
worker_IP=request.args.get('ip')
2023-08-25 12:25:23 +10:00
worker_PRIV=request.args.get('priv')
2023-08-16 13:47:49 +10:00
# Get API header
api_key = request.headers.get('key')
2023-08-25 12:25:23 +10:00
if api_key == None or worker == None or worker_IP == None or worker_PRIV == None:
2023-08-16 16:59:57 +10:00
return jsonify({'error': 'Invalid API key or worker info', 'success': 'false'})
2023-08-16 13:47:49 +10:00
if api_key != os.getenv('WORKER_KEY'):
return jsonify({'error': 'Invalid API key', 'success': 'false'})
# Check worker file
try:
workers_file = open('/data/workers.txt', 'r')
2023-08-16 13:47:49 +10:00
except FileNotFoundError:
workers_file = open('/data/workers.txt', 'w')
2023-08-16 13:47:49 +10:00
workers_file.close()
workers_file = open('/data/workers.txt', 'r')
2023-08-16 13:47:49 +10:00
# Check if worker already exists
if worker in workers_file.read():
return jsonify({'error': 'Worker already exists', 'success': 'false'})
workers_file.close()
# Add worker to file
workers_file = open('/data/workers.txt', 'a')
2023-08-25 12:25:23 +10:00
workers_file.write(worker + ":" + worker_PRIV + ":"+ worker_IP + '\n')
2023-08-16 13:47:49 +10:00
workers_file.close()
2023-08-16 16:59:57 +10:00
online=True
2023-08-25 12:25:23 +10:00
resp=requests.get("http://"+worker_PRIV + ":5000/ping",timeout=2)
2023-08-16 16:59:57 +10:00
if (resp.status_code != 200):
online=False
return jsonify({'success': 'true', 'worker': worker, 'online': online})
2023-08-16 13:47:49 +10:00
2023-08-17 12:45:36 +10:00
@app.route('/list-workers', methods=['GET'])
def list_workers():
# Get API header
api_key = request.headers.get('key')
if api_key == None:
return jsonify({'error': 'Invalid API key', 'success': 'false'})
if api_key != os.getenv('WORKER_KEY'):
return jsonify({'error': 'Invalid API key', 'success': 'false'})
# Check worker file
try:
workers_file = open('/data/workers.txt', 'r')
except FileNotFoundError:
workers_file = open('/data/workers.txt', 'w')
workers_file.close()
workers_file = open('/data/workers.txt', 'r')
workers = workers_file.readlines()
workers_file.close()
2023-08-24 11:55:46 +10:00
# Check if there are any workers (by seeing if there are any :)
2023-08-24 11:52:13 +10:00
if len(workers) == 0:
return jsonify({'error': 'No workers available', 'success': 'false'})
2023-08-17 12:45:36 +10:00
worker_list = []
for worker in workers:
# Check worker status
2023-08-24 12:03:20 +10:00
if not worker.__contains__(':'):
2023-08-25 11:42:31 +10:00
continue
2023-08-24 12:03:20 +10:00
2023-08-17 12:45:36 +10:00
online=True
2023-08-25 17:31:32 +10:00
try:
resp=requests.get("http://"+worker.split(':')[1].strip('\n') + ":5000/status",timeout=2)
if (resp.status_code != 200):
online=False
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': 0, 'status': 'offline'})
continue
sites = resp.json()['num_sites']
availability = resp.json()['availability']
if availability == True:
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': sites, 'status': 'ready'})
else:
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': sites, 'status': 'full'})
except:
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': 'False', 'sites': 0, 'status': 'offline'})
2023-08-17 12:45:36 +10:00
continue
2023-08-25 17:31:32 +10:00
2023-08-25 11:42:31 +10:00
if len(worker_list) == 0:
return jsonify({'error': 'No workers available', 'success': 'false'})
2023-08-17 12:45:36 +10:00
return jsonify({'success': 'true', 'workers': worker_list})
@app.route('/site-info', methods=['GET'])
def site_status():
domain = request.args.get('domain')
domain = domain.lower()
if domain == None:
return jsonify({'error': 'Invalid domain', 'success': 'false'})
# Check if domain exists
if not site_exists(domain):
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
# Get worker
worker = site_worker(domain)
if worker == None:
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
# Get worker ip
2023-08-25 12:25:23 +10:00
ip = workerIP_PRIV(worker)
# Get TLSA record
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
json = resp.json()
2023-08-25 12:25:23 +10:00
publicIP = workerIP(worker)
if "tlsa" in json:
tlsa = json['tlsa']
2023-08-25 12:25:23 +10:00
return jsonify({'success': 'true', 'domain': domain, 'ip': publicIP, 'tlsa': tlsa})
else:
2023-08-25 12:25:23 +10:00
return jsonify({'success': 'false', 'domain': domain, 'ip': publicIP, 'tlsa': 'none','error': 'No TLSA record found'})
2023-08-17 13:27:57 +10:00
@app.route('/tlsa', methods=['GET'])
def tlsa():
domain = request.args.get('domain')
domain = domain.lower()
2023-08-17 13:27:57 +10:00
if domain == None:
return jsonify({'error': 'Invalid domain', 'success': 'false'})
# Check if domain exists
if not site_exists(domain):
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
# Get worker
worker = site_worker(domain)
if worker == None:
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
# Get worker ip
2023-08-25 12:25:23 +10:00
ip = workerIP_PRIV(worker)
2023-08-17 13:27:57 +10:00
# Get TLSA record
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
2023-08-17 13:27:57 +10:00
return resp.json()
2023-08-16 13:47:49 +10:00
2023-08-24 16:13:24 +10:00
2023-08-24 16:17:27 +10:00
@app.route('/stripe', methods=['POST'])
2023-08-24 16:41:38 +10:00
def stripeapi():
payload = request.data
stripe.api_key = os.getenv('STRIPE_SECRET')
endpoint_secret = os.getenv('STRIPE_ENDPOINT_SECRET')
2023-08-24 16:44:17 +10:00
sig_header = request.headers.get('Stripe-Signature')
2023-08-24 16:41:38 +10:00
events = None
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
return jsonify({'success': 'false'})
except stripe.error.SignatureVerificationError as e:
return jsonify({'success': 'false'})
2023-08-24 17:18:24 +10:00
2023-08-24 16:41:38 +10:00
if event.type == 'payment_intent.succeeded':
# Only for payments for licences
2023-08-24 16:53:39 +10:00
payment_intent = event.data.object
if payment_intent['amount'] != 1000:
return jsonify({'success': 'true'})
if payment_intent['description'] != "Subscription creation":
return jsonify({'success': 'true'})
2023-08-24 16:53:39 +10:00
# Get email
email = payment_intent['receipt_email']
# Create licence key
licence_key = os.urandom(16).hex()
# Add licence key to file
key_file = open('/data/licence_key.txt', 'a')
key_file.write(licence_key + '\n')
key_file.close()
# Send email
host = os.getenv('SMTP_HOST')
port = os.getenv('SMTP_PORT')
user = os.getenv('SMTP_USER')
password = os.getenv('SMTP_PASS')
from_email = os.getenv('SMTP_FROM')
if from_email == None:
2023-08-24 17:18:24 +10:00
from_email = "Hosting <"+user + ">"
2023-08-24 16:53:39 +10:00
context = ssl.create_default_context()
with smtplib.SMTP_SSL(host, port, context=context) as server:
server.login(user, password)
2023-08-24 17:18:24 +10:00
message = "From: " + from_email + "\nTo: " + email + \
2023-08-24 17:11:42 +10:00
"\nSubject: Your Licence key\n\nHello,\n\n"\
+"This email contains your licence key for your new wordpress site.\n" \
2023-09-02 14:14:00 +10:00
+"You can redeem this key via the discord bot or at https://hnshosting.au/register\n\n"\
2023-08-24 17:11:42 +10:00
+"Your licence key is: " + licence_key +"\nThanks,\nHNSHosting"
2023-08-24 16:57:05 +10:00
server.sendmail(from_email, email, message)
2023-08-24 16:53:39 +10:00
2023-08-24 17:18:24 +10:00
print('Licence sent via email for stripe payment', flush=True)
2023-08-24 16:41:38 +10:00
else:
print('Unhandled event type {}'.format(event.type))
2023-08-24 16:13:24 +10:00
return jsonify({'success': 'true'})
2023-08-16 13:47:49 +10:00
def get_sites_count():
# If file doesn't exist, create it
try:
sites_file = open('/data/sites.txt', 'r')
2023-08-16 13:47:49 +10:00
except FileNotFoundError:
sites_file = open('/data/sites.txt', 'w')
2023-08-16 13:47:49 +10:00
sites_file.close()
sites_file = open('/data/sites.txt', 'r')
2023-08-16 13:47:49 +10:00
num=len(sites_file.readlines())
sites_file.close()
# Return number of lines in file
return num
def site_exists(domain):
# If file doesn't exist, create it
try:
sites_file = open('/data/sites.txt', 'r')
2023-08-16 13:47:49 +10:00
except FileNotFoundError:
sites_file = open('/data/sites.txt', 'w')
2023-08-16 13:47:49 +10:00
sites_file.close()
sites_file = open('/data/sites.txt', 'r')
2023-08-16 13:47:49 +10:00
contains_site = False
2023-08-16 16:59:57 +10:00
for line in sites_file.readlines():
if domain == line.split(':')[0]:
contains_site = True
break
2023-08-16 13:47:49 +10:00
sites_file.close()
return contains_site
2023-08-16 16:59:57 +10:00
def site_worker(domain):
# If file doesn't exist, create it
try:
sites_file = open('/data/sites.txt', 'r')
2023-08-16 16:59:57 +10:00
except FileNotFoundError:
sites_file = open('/data/sites.txt', 'w')
2023-08-16 16:59:57 +10:00
sites_file.close()
sites_file = open('/data/sites.txt', 'r')
2023-08-16 16:59:57 +10:00
worker = None
for line in sites_file.readlines():
if domain == line.split(':')[0]:
worker = line.split(':')[1].strip('\n')
break
sites_file.close()
return worker
2023-08-25 12:25:23 +10:00
def workerIP_PRIV(worker):
# If file doesn't exist, create it
try:
workers_file = open('/data/workers.txt', 'r')
except FileNotFoundError:
workers_file = open('/data/workers.txt', 'w')
workers_file.close()
workers_file = open('/data/workers.txt', 'r')
ip = None
for line in workers_file.readlines():
if worker == line.split(':')[0]:
2023-09-16 17:10:20 +10:00
ip = line.split(':')[1].strip('\n')
2023-08-25 12:25:23 +10:00
break
workers_file.close()
return ip
def workerIP(worker):
# If file doesn't exist, create it
try:
workers_file = open('/data/workers.txt', 'r')
except FileNotFoundError:
workers_file = open('/data/workers.txt', 'w')
workers_file.close()
workers_file = open('/data/workers.txt', 'r')
ip = None
for line in workers_file.readlines():
if worker == line.split(':')[0]:
2023-09-16 17:10:20 +10:00
ip = line.split(':')[2].strip('\n')
break
workers_file.close()
return ip
2023-08-16 13:47:49 +10:00
2023-08-25 15:51:47 +10:00
# Home page
@app.route('/')
def home():
2023-09-02 13:29:12 +10:00
# Show index template
2023-08-25 15:51:47 +10:00
# Get site info
sites = []
try:
sites_file = open('/data/sites.txt', 'r')
sites = sites_file.readlines()
sites_file.close()
except FileNotFoundError:
pass
2023-08-25 23:26:44 +10:00
2023-09-02 13:29:12 +10:00
return render_template('index.html', site_count = str(len(sites)))
2023-08-25 16:29:25 +10:00
2023-09-02 13:48:10 +10:00
# Register page
2023-09-03 13:48:26 +10:00
@app.route('/register', methods=['GET'])
2023-09-02 13:48:10 +10:00
def register():
2023-09-02 14:03:12 +10:00
buy_licence_link = os.getenv('BUY_LICENCE_LINK')
2023-09-02 13:48:10 +10:00
# Show register template
2023-09-03 13:48:26 +10:00
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="")
@app.route('/register', methods=['POST'])
def register_post():
buy_licence_link = os.getenv('BUY_LICENCE_LINK')
if 'licence' not in request.form:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No licence key provided")
licence_key = request.form['licence']
# Check if licence key is valid
key_file = open('/data/licence_key.txt', 'r')
valid_key = False
for line in key_file.readlines():
if licence_key == line.strip('\n'):
valid_key = True
break
key_file.close()
if not valid_key:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Invalid licence key")
# Get domain
domain = request.form['domain']
if domain == None:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No domain provided")
# Check if domain already exists
if site_exists(domain):
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Domain already exists")
# Check if domain contains http:// or https://
if domain.startswith("http://") or domain.startswith("https://"):
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Domain should not contain http:// or https://")
# Set domain to lowercase
domain = domain.lower()
2023-09-03 13:48:26 +10:00
# Check if worker file exists
workers = None
try:
worker_file = open('/data/workers.txt', 'r')
workers = worker_file.readlines()
worker_file.close()
except FileNotFoundError:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support")
# Get a worker that has available slots
worker = None
for line in workers:
if not line.__contains__(':'):
continue
ip = line.split(':')[1].strip('\n')
resp=requests.get("http://"+ip + ":5000/status",timeout=2)
if (resp.status_code == 200):
if resp.json()['availability'] == True:
worker = line
break
if worker == None:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support")
# Delete licence key
key_file = open('/data/licence_key.txt', 'r')
lines = key_file.readlines()
key_file.close()
key_file = open('/data/licence_key.txt', 'w')
for line in lines:
if line.strip("\n") != licence_key:
key_file.write(line)
key_file.close()
# Add domain to file
sites_file = open('/data/sites.txt', 'a')
sites_file.write(domain + ':' + worker.split(':')[0] + '\n')
sites_file.close()
# Send worker request
requests.post("http://"+ worker.split(':')[1].strip('\n') + ":5000/new-site?domain=" + domain)
return redirect('/success?domain=' + domain + '&status=creating')
@app.route('/success')
2023-09-25 15:07:56 +10:00
@app.route('/info')
2023-09-03 13:48:26 +10:00
def success():
if 'domain' not in request.args:
return redirect('/')
domain = request.args.get('domain')
domain = domain.lower()
2023-09-03 13:48:26 +10:00
if not site_exists(domain):
2023-09-20 22:11:58 +10:00
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="")
2023-09-03 13:48:26 +10:00
if 'status' not in request.args:
# Get worker
worker = site_worker(domain)
if worker == None:
2023-09-20 22:11:58 +10:00
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="Error: Domain does not exist<br>Please contact support")
2023-09-03 13:48:26 +10:00
# Get worker ip
ip = workerIP_PRIV(worker)
# Get TLSA record
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
json = resp.json()
publicIP = workerIP(worker)
if "tlsa" in json:
tlsa = json['tlsa']
2023-09-20 22:29:27 +10:00
return render_template('success.html', title="Your site is ready!",message="Success<br>Domain: <code>" + domain + "</code><br>IP: <code>" + publicIP + "</code><br>TLSA: <code>" + tlsa + "</code><br>Make sure to add the TLSA record to <code>_443._tcp." + domain + "</code> or <code>*." + domain + "</code>")
2023-09-03 13:48:26 +10:00
else:
2023-09-20 22:29:27 +10:00
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="Domain: <code>" + domain + "</code><br>IP: <code>" + publicIP + "</code><br>TLSA: Pending<br>No TLSA record found")
2023-09-03 13:48:26 +10:00
elif request.args.get('status') == 'creating':
return render_template('success.html')
2023-09-25 15:07:56 +10:00
2023-09-18 14:42:43 +10:00
@app.route('/site-count')
def site_count_route():
return str(get_sites_count())
2023-09-03 13:48:26 +10:00
2023-09-02 13:48:10 +10:00
2023-08-25 16:29:25 +10:00
# Admin page
2023-08-25 16:36:53 +10:00
@app.route('/admin')
2023-08-25 16:29:25 +10:00
def admin():
# Check if logged in
2023-08-25 16:32:50 +10:00
login_key = request.cookies.get('login_key')
2023-08-25 16:29:25 +10:00
2023-08-25 16:36:53 +10:00
if login_key == None:
2023-08-25 16:51:19 +10:00
return "<h1>Admin</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
2023-08-25 16:36:53 +10:00
if login_key not in logins:
2023-08-25 16:51:19 +10:00
return "<h1>Admin</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
2023-08-25 16:36:53 +10:00
2023-08-25 17:07:41 +10:00
# Show some admin stuff
licences = []
try:
licences_file = open('/data/licence_key.txt', 'r')
licences = licences_file.readlines()
licences_file.close()
except FileNotFoundError:
pass
# Create html page
html = "<h1>Admin</h1><br>"
html += "<h2>Licences</h2>"
html += "<p>Number of licences: " + str(len(licences)) + "</p>"
html += "<p>Licences:</p>"
html += "<ul>"
for licence in licences:
html += "<li>" + licence.strip('\n') + "</li>"
html += "</ul>"
html += "<h2>API</h2>"
html += "<p>API key: " + os.getenv('LICENCE_KEY') + "</p>"
html += "<p>Worker key: " + os.getenv('WORKER_KEY') + "</p>"
html += "<h2>Stripe</h2>"
# Check if stripe is enabled
if os.getenv('STRIPE_SECRET') == None:
html += "<p>Stripe is not enabled</p>"
else:
html += "<p>Stripe is enabled</p>"
html += "<br><br><h2>Workers</h2>"
2023-08-25 17:13:34 +10:00
workers = []
try:
workers_file = open('/data/workers.txt', 'r')
workers = workers_file.readlines()
workers_file.close()
except FileNotFoundError:
pass
for worker in workers:
2023-08-25 17:18:37 +10:00
if not worker.__contains__(':'):
continue
2023-08-25 17:13:34 +10:00
html += "<p>Name: " + worker.split(':')[0] + " | Public IP " + worker.split(':')[2].strip('\n') + " | Private IP " + worker.split(':')[1]
# Check worker status
online=True
2023-08-25 17:31:32 +10:00
try:
resp=requests.get("http://"+worker.split(':')[1].strip('\n') + ":5000/status",timeout=2)
if (resp.status_code != 200):
html += " | Status: Offline"
else:
html += " | Status: Online | Sites: " + str(resp.json()['num_sites']) + " | Availability: " + str(resp.json()['availability'])
except:
2023-08-25 17:13:34 +10:00
html += " | Status: Offline"
2023-08-25 17:31:32 +10:00
2023-08-25 17:13:34 +10:00
html += "</p>"
2023-08-25 17:07:41 +10:00
html += "<h2>Sites</h2>"
sites = []
try:
sites_file = open('/data/sites.txt', 'r')
sites = sites_file.readlines()
sites_file.close()
except FileNotFoundError:
pass
for site in sites:
2023-08-25 17:18:37 +10:00
if not site.__contains__(':'):
continue
domain = site.split(':')[0]
2023-09-25 15:14:16 +10:00
html += "<p>Domain: <a href='https://"+ domain + "'>" + domain + "</a> | Worker: " + site.split(':')[1].strip('\n') + " | <a href='/info?domain=" + domain + "'>Info</a></p>"
2023-08-25 17:07:41 +10:00
html += "<br><br>"
2023-08-25 17:18:37 +10:00
# Form to add worker
html += "<h2>Add worker</h2>"
html += "<form action='/new-worker' method='POST'>"
html += "<p>Name: <input type='text' name='name'></p>"
html += "<p>Public IP: <input type='text' name='ip'></p>"
html += "<p>Private IP: <input type='text' name='priv'></p>"
html += "<input type='submit' value='Add worker'>"
html += "</form>"
html += "<br><h2><a href='/licence'>Add Licence</a></h2><br>"
# Form to add site
html += "<h2>Add site</h2>"
html += "<form action='/add-site' method='POST'>"
html += "<p>Domain: <input type='text' name='domain'></p>"
html += "<input type='submit' value='Add site'>"
html += "</form>"
2023-08-25 17:18:37 +10:00
html += "<br><a href='/logout'>Logout</a></h2>"
2023-08-25 17:07:41 +10:00
return html
2023-08-25 16:36:53 +10:00
@app.route('/add-site', methods=['POST'])
2023-08-25 17:48:42 +10:00
def addsite():
2023-08-25 17:57:51 +10:00
# Check for licence key
if 'licence' not in request.form:
# Check cookie
login_key = request.cookies.get('login_key')
if login_key == None:
return redirect('/admin')
if login_key not in logins:
return redirect('/admin')
else:
# Use licence key
licence_key = request.form['licence']
# Check if licence key is valid
key_file = open('/data/licence_key.txt', 'r')
valid_key = False
for line in key_file.readlines():
if licence_key == line.strip('\n'):
valid_key = True
break
key_file.close()
if not valid_key:
return jsonify({'error': 'Invalid licence', 'success': 'false'})
# Delete licence key
key_file = open('/data/licence_key.txt', 'r')
lines = key_file.readlines()
key_file.close()
key_file = open('/data/licence_key.txt', 'w')
for line in lines:
if line.strip("\n") != licence_key:
key_file.write(line)
key_file.close()
# Get domain
2023-08-25 18:01:49 +10:00
domain = request.form['domain']
if domain == None:
2023-08-25 18:01:49 +10:00
return jsonify({'error': 'No domain sent', 'success': 'false'})
# Check if domain already exists
if site_exists(domain):
return jsonify({'error': 'Domain already exists', 'success': 'false'})
# Check if domain contains http:// or https://
if domain.startswith("http://") or domain.startswith("https://"):
return jsonify({'error': 'Domain should not contain http:// or https://', 'success': 'false'})
domain = domain.lower()
# Remove any trailing / or .
if domain.endswith('/'):
domain = domain.removesuffix('/')
if domain.endswith('.'):
domain = domain.removesuffix('.')
# Check if worker file exists
workers = None
try:
worker_file = open('/data/workers.txt', 'r')
workers = worker_file.readlines()
worker_file.close()
except FileNotFoundError:
return jsonify({'error': 'No workers available', 'success': 'false'})
# Get a worker that has available slots
worker = None
for line in workers:
if not line.__contains__(':'):
continue
ip = line.split(':')[1].strip('\n')
resp=requests.get("http://"+ip + ":5000/status",timeout=2)
if (resp.status_code == 200):
if resp.json()['availability'] == True:
worker = line
break
if worker == None:
return jsonify({'error': 'No workers available', 'success': 'false'})
# Add domain to file
sites_file = open('/data/sites.txt', 'a')
sites_file.write(domain + ':' + worker.split(':')[0] + '\n')
sites_file.close()
# Send worker request
requests.post("http://"+ worker.split(':')[1].strip('\n') + ":5000/new-site?domain=" + domain)
2023-08-25 17:57:51 +10:00
html = "<h1>Site creating...</h1><br>"
html += "<p>Domain: " + domain + "</p>"
html += "<p>Worker: " + worker.split(':')[0] + "</p>"
html += "<p>Worker IP: " + worker.split(':')[1].strip('\n') + "</p>"
2023-08-25 18:13:36 +10:00
html += "<p><a href='/info?domain=" + domain + "'>Check status</a></p>"
2023-08-25 17:57:51 +10:00
return html
@app.route('/licence')
def licence():
# Check cookie
login_key = request.cookies.get('login_key')
if login_key == None:
return redirect('/admin')
if login_key not in logins:
return redirect('/admin')
2023-08-25 17:48:42 +10:00
licence_key = os.urandom(16).hex()
# Add license key to file
key_file = open('/data/licence_key.txt', 'a')
key_file.write(licence_key + '\n')
key_file.close()
return "<h1>Licence key</h1><br><p>" + licence_key + "</p><br><a href='/admin'>Back</a>"
2023-08-25 17:18:37 +10:00
@app.route('/new-worker', methods=['POST'])
def new_worker():
# Check cookie
login_key = request.cookies.get('login_key')
if login_key == None:
return redirect('/admin')
if login_key not in logins:
return redirect('/admin')
worker = request.form['name']
worker_IP = request.form['ip']
worker_PRIV = request.form['priv']
# Check worker file
try:
workers_file = open('/data/workers.txt', 'r')
except FileNotFoundError:
workers_file = open('/data/workers.txt', 'w')
workers_file.close()
workers_file = open('/data/workers.txt', 'r')
2023-08-25 16:36:53 +10:00
2023-08-25 17:18:37 +10:00
# Check if worker already exists
if worker in workers_file.read():
return jsonify({'error': 'Worker already exists', 'success': 'false'})
workers_file.close()
# Add worker to file
workers_file = open('/data/workers.txt', 'a')
workers_file.write(worker + ":" + worker_PRIV + ":"+ worker_IP + '\n')
workers_file.close()
return redirect('/admin')
@app.route('/logout')
def logout():
login_key = request.cookies.get('login_key')
if login_key == None:
return redirect('/admin')
if login_key not in logins:
return redirect('/admin')
logins.remove(login_key)
return redirect('/admin')
2023-08-25 16:36:53 +10:00
@app.route('/login', methods=['POST'])
2023-08-25 16:38:34 +10:00
def login():
2023-08-25 16:47:22 +10:00
# Handle login
print('Login attempt', flush=True)
2023-08-25 17:07:41 +10:00
# Check if form contains password
if 'password' not in request.form:
print('Login failed', flush=True)
return redirect('/failed-login')
2023-08-25 16:47:22 +10:00
password = request.form['password']
if os.getenv('ADMIN_KEY') == password:
print('Login success', flush=True)
# Generate login key
login_key = os.urandom(32).hex()
logins.append(login_key)
# Set cookie
resp = make_response(redirect('/admin'))
resp.set_cookie('login_key', login_key)
return resp
print('Login failed', flush=True)
return redirect('/failed-login')
@app.route('/failed-login')
def failed_login():
2023-08-25 16:51:19 +10:00
return "<h1>Failed login</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
2023-08-25 16:29:25 +10:00
2023-08-25 23:26:44 +10:00
# Assets
@app.route('/assets/<path:path>')
def send_report(path):
2023-09-02 13:31:47 +10:00
return send_from_directory('templates/assets', path)
2023-08-25 15:51:47 +10:00
2023-11-17 17:01:14 +11:00
@app.route('/terms')
def terms():
return render_template('terms.html')
# 404 route
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
2023-08-25 15:51:47 +10:00
2023-09-02 13:31:47 +10:00
2023-08-16 13:47:49 +10:00
# Start the server
if __name__ == '__main__':
2023-08-16 17:05:15 +10:00
app.run(debug=False, port=5000, host='0.0.0.0')