Compare commits

..

No commits in common. "main" and "feature/dashboard" have entirely different histories.

30 changed files with 93 additions and 610 deletions

View File

@ -10,7 +10,7 @@ on:
jobs: jobs:
Build Master: Build Master:
runs-on: [ubuntu-latest, arm] runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -51,7 +51,7 @@ jobs:
Build Bot: Build Bot:
runs-on: [ubuntu-latest, arm] runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -8,7 +8,7 @@ on:
jobs: jobs:
Build Master: Build Master:
runs-on: [ubuntu-latest,arm] runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -34,7 +34,7 @@ jobs:
docker push git.woodburn.au/nathanwoodburn/hnshosting-master:release docker push git.woodburn.au/nathanwoodburn/hnshosting-master:release
Build Bot: Build Bot:
runs-on: [ubuntu-latest,arm] runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -115,15 +115,4 @@ Enable the free mode by setting the following environment variable.
This will allow you to create a wordpress site without using a licence key using the /createsite command. This will allow you to create a wordpress site without using a licence key using the /createsite command.
``` ```
FREE_MODE: true FREE_MODE: true
``` ```
## Hip2
HIP2 allows sending HNS to a domain.
To enable HIP2 on your wordpress site you should
1. Download the [HIP2 plugin](https://git.woodburn.au/nathanwoodburn/hnshosting-wp/raw/branch/main/assets/hns-wallet-plugin.zip)
2. Upload the plugin to your wordpress site
3. Activate the plugin
4. Go to the settings page and enter your HNS wallet address
5. Ensure it works by settings the permalink to post name and saving

Binary file not shown.

View File

@ -51,7 +51,6 @@ async def listworkers(ctx):
await ctx.response.send_message(f"Error listing workers\n" + r.text,ephemeral=True) await ctx.response.send_message(f"Error listing workers\n" + r.text,ephemeral=True)
else: else:
await ctx.response.send_message("You do not have permission to use this command",ephemeral=True) await ctx.response.send_message("You do not have permission to use this command",ephemeral=True)
update_bot_status()
@tree.command(name="licence", description="Gets a licence key") @tree.command(name="licence", description="Gets a licence key")
async def license(ctx): async def license(ctx):
@ -71,14 +70,6 @@ async def license(ctx):
@tree.command(name="createsite", description="Create a new WordPress site") @tree.command(name="createsite", description="Create a new WordPress site")
async def createsite(ctx, domain: str, licence: str = None): async def createsite(ctx, domain: str, licence: str = None):
# Verify domain is valid
if domain == None:
await ctx.response.send_message("You must specify a domain",ephemeral=True)
return
if "http://" in domain or "https://" in domain:
await ctx.response.send_message("You must specify a domain without http:// or https://",ephemeral=True)
return
if FREE_LICENCE == True: # If free licences are enabled then auto generate a licence if FREE_LICENCE == True: # If free licences are enabled then auto generate a licence
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-licence",headers={"key":os.getenv('LICENCE_KEY')}) r = requests.post(f"http://{Master_IP}:{Master_Port}/add-licence",headers={"key":os.getenv('LICENCE_KEY')})
if r.status_code == 200: if r.status_code == 200:
@ -88,12 +79,12 @@ async def createsite(ctx, domain: str, licence: str = None):
else: else:
await ctx.response.send_message(f"Error getting license\n" + json['error']) await ctx.response.send_message(f"Error getting license\n" + json['error'])
return return
r = requests.post(f"http://{Master_IP}:{Master_Port}/new-site?domain={domain}",headers={"key":licence}) r = requests.post(f"http://{Master_IP}:{Master_Port}/new-site?domain={domain}",headers={"key":licence})
if r.status_code == 200: if r.status_code == 200:
json = r.json() json = r.json()
if json['success'] == "true": if json['success'] == "true":
await ctx.response.send_message(f"Site https://{domain} creating...\nI'll send you a message when it's ready") await ctx.response.send_message(f"Site {domain} creating...\nI'll send you a message when it's ready")
ready = False ready = False
while ready == False: while ready == False:
@ -104,7 +95,7 @@ async def createsite(ctx, domain: str, licence: str = None):
r = requests.get(f"http://{Master_IP}:{Master_Port}/site-info?domain={domain}") r = requests.get(f"http://{Master_IP}:{Master_Port}/site-info?domain={domain}")
json = r.json() json = r.json()
if json['success'] == "true": if json['success'] == "true":
await ctx.user.send(f"Site https://{domain} is ready!\nHere is the site info for {json['domain']}\nA: `{json['ip']}`\nTLSA: `{json['tlsa']}`\nMake sure you put the TLSA in either `_443._tcp.{domain}` or `*.{domain}`") await ctx.user.send(f"Site {domain} is ready!\nHere is the site info for {json['domain']}\nA: `{json['ip']}`\nTLSA: `{json['tlsa']}`\nMake sure you put the TLSA in either `_443._tcp.{domain}` or `*.{domain}`")
else: else:
await ctx.user.send(f"Error getting site info\n" + json['error']) await ctx.user.send(f"Error getting site info\n" + json['error'])
@ -113,7 +104,6 @@ async def createsite(ctx, domain: str, licence: str = None):
await ctx.response.send_message(f"Error creating site\n" + json['error']) await ctx.response.send_message(f"Error creating site\n" + json['error'])
else: else:
await ctx.response.send_message(f"Error creating site\n" + r.text) await ctx.response.send_message(f"Error creating site\n" + r.text)
update_bot_status()
@tree.command(name="siteinfo", description="Get info about a WordPress site") @tree.command(name="siteinfo", description="Get info about a WordPress site")
@ -138,17 +128,6 @@ async def check_site_ready(domain):
return False return False
else: else:
return False return False
def get_site_count():
r = requests.get(f"http://{Master_IP}:{Master_Port}/site-count")
if r.status_code == 200:
return r.text
else:
return "Error getting site count\n" + r.text
def update_bot_status():
site_count = get_site_count()
client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over " + site_count + " wordpress sites")))
# When the bot is ready # When the bot is ready
@client.event @client.event
@ -156,9 +135,6 @@ async def on_ready():
global ADMINID global ADMINID
ADMINID = client.application.owner.id ADMINID = client.application.owner.id
await tree.sync() await tree.sync()
await client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over HNSHosting wordpress")))
# Get the number of sites
site_count = get_site_count()
await client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over " + site_count + " wordpress sites")))
client.run(TOKEN) client.run(TOKEN)

View File

@ -1,10 +0,0 @@
html {
background-color: black;
color: white;
font-family: 'Roboto', sans-serif;
font-size: 16px;
text-align: center;
}
li {
list-style-type: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,4 +1,4 @@
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory from flask import Flask, make_response, redirect, request, jsonify
import dotenv import dotenv
import os import os
import requests import requests
@ -206,7 +206,6 @@ def list_workers():
@app.route('/site-info', methods=['GET']) @app.route('/site-info', methods=['GET'])
def site_status(): def site_status():
domain = request.args.get('domain') domain = request.args.get('domain')
domain = domain.lower()
if domain == None: if domain == None:
return jsonify({'error': 'Invalid domain', 'success': 'false'}) return jsonify({'error': 'Invalid domain', 'success': 'false'})
@ -233,10 +232,39 @@ def site_status():
else: else:
return jsonify({'success': 'false', 'domain': domain, 'ip': publicIP, 'tlsa': 'none','error': 'No TLSA record found'}) return jsonify({'success': 'false', 'domain': domain, 'ip': publicIP, 'tlsa': 'none','error': 'No TLSA record found'})
@app.route('/info')
def site_status_human():
domain = request.args.get('domain')
if domain == None:
return "<h1>Invalid domain</h1>"
# Check if domain exists
if not site_exists(domain):
return "<h1>Domain does not exist</h1>"
# Get worker
worker = site_worker(domain)
if worker == None:
return "<h1>Domain does not exist</h1>"
# 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']
return "<h1>Domain: " + domain + "</h1><br><p>IP: " + publicIP + "</p><br><p>TLSA: " + tlsa + "</p><br><p>Make sure to add the TLSA record to `_443._tcp." + domain + "` or `*." + domain + "`</p>"
else:
return "<h1>Domain: " + domain + "</h1><br><p>IP: " + publicIP + "</p><br><p>TLSA: none</p><br><p>No TLSA record found</p>"
@app.route('/tlsa', methods=['GET']) @app.route('/tlsa', methods=['GET'])
def tlsa(): def tlsa():
domain = request.args.get('domain') domain = request.args.get('domain')
domain = domain.lower()
if domain == None: if domain == None:
return jsonify({'error': 'Invalid domain', 'success': 'false'}) return jsonify({'error': 'Invalid domain', 'success': 'false'})
@ -277,14 +305,7 @@ def stripeapi():
return jsonify({'success': 'false'}) return jsonify({'success': 'false'})
if event.type == 'payment_intent.succeeded': if event.type == 'payment_intent.succeeded':
# Only for payments for licences
payment_intent = event.data.object payment_intent = event.data.object
if payment_intent['amount'] != 1000:
return jsonify({'success': 'true'})
if payment_intent['description'] != "Subscription creation":
return jsonify({'success': 'true'})
# Get email # Get email
email = payment_intent['receipt_email'] email = payment_intent['receipt_email']
# Create licence key # Create licence key
@ -308,7 +329,7 @@ def stripeapi():
message = "From: " + from_email + "\nTo: " + email + \ message = "From: " + from_email + "\nTo: " + email + \
"\nSubject: Your Licence key\n\nHello,\n\n"\ "\nSubject: Your Licence key\n\nHello,\n\n"\
+"This email contains your licence key for your new wordpress site.\n" \ +"This email contains your licence key for your new wordpress site.\n" \
+"You can redeem this key via the discord bot or at https://hnshosting.au/register\n\n"\ +"You can redeem this key via the discord bot or api.\n\n"\
+"Your licence key is: " + licence_key +"\nThanks,\nHNSHosting" +"Your licence key is: " + licence_key +"\nThanks,\nHNSHosting"
server.sendmail(from_email, email, message) server.sendmail(from_email, email, message)
@ -380,7 +401,7 @@ def workerIP_PRIV(worker):
ip = None ip = None
for line in workers_file.readlines(): for line in workers_file.readlines():
if worker == line.split(':')[0]: if worker == line.split(':')[0]:
ip = line.split(':')[1].strip('\n') ip = line.split(':')[2].strip('\n')
break break
workers_file.close() workers_file.close()
@ -398,7 +419,7 @@ def workerIP(worker):
ip = None ip = None
for line in workers_file.readlines(): for line in workers_file.readlines():
if worker == line.split(':')[0]: if worker == line.split(':')[0]:
ip = line.split(':')[2].strip('\n') ip = line.split(':')[1].strip('\n')
break break
workers_file.close() workers_file.close()
@ -408,7 +429,17 @@ def workerIP(worker):
# Home page # Home page
@app.route('/') @app.route('/')
def home(): def home():
# Show index template # Show stats and info
# Get worker info
workers = []
try:
workers_file = open('/data/workers.txt', 'r')
workers = workers_file.readlines()
workers_file.close()
except FileNotFoundError:
pass
# Get site info # Get site info
sites = [] sites = []
try: try:
@ -418,132 +449,44 @@ def home():
except FileNotFoundError: except FileNotFoundError:
pass pass
# Get licence info
return render_template('index.html', site_count = str(len(sites))) licences = []
# Register page
@app.route('/register', methods=['GET'])
def register():
buy_licence_link = os.getenv('BUY_LICENCE_LINK')
# Show register template
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()
# Check if worker file exists
workers = None
try: try:
worker_file = open('/data/workers.txt', 'r') licences_file = open('/data/licence_key.txt', 'r')
workers = worker_file.readlines() licences = licences_file.readlines()
worker_file.close() licences_file.close()
except FileNotFoundError: except FileNotFoundError:
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support") pass
# 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: # Create html page
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support") html = "<h1>Welcome</h1><br>"
html += "<h2>Create a site</h2>"
# Delete licence key html += "<form action='/add-site' method='POST'>"
key_file = open('/data/licence_key.txt', 'r') html += "<p>Domain: <input type='text' name='domain'></p>"
lines = key_file.readlines() html += "<p>Licence key: <input type='text' name='licence'></p>"
key_file.close() html += "<input type='submit' value='Create site'>"
key_file = open('/data/licence_key.txt', 'w') html += "</form>"
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')
@app.route('/info')
def success():
if 'domain' not in request.args:
return redirect('/')
domain = request.args.get('domain')
domain = domain.lower()
if not site_exists(domain):
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="")
if 'status' not in request.args:
# Get worker
worker = site_worker(domain)
if worker == None:
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="Error: Domain does not exist<br>Please contact support")
# 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']
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>")
else:
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")
elif request.args.get('status') == 'creating':
return render_template('success.html')
@app.route('/site-count')
def site_count_route():
return str(get_sites_count())
html += "<br><h2>Stats</h2><br>"
html += "<h2>Workers</h2>"
html += "<p>Number of workers: " + str(len(workers)) + "</p>"
html += "<p>Workers:</p>"
html += "<ul>"
for worker in workers:
html += "<li>Name: " + worker.split(':')[0] + " | IP " + worker.split(':')[2].strip('\n') + "</li>"
html += "</ul>"
html += "<h2>Sites</h2>"
html += "<p>Number of sites: " + str(len(sites)) + "</p>"
html += "<p>Sites:</p>"
html += "<ul>"
for site in sites:
html += "<li>Domain: " + site.split(':')[0] + " | Worker: " + site.split(':')[1].strip('\n') + "</li>"
html += "</ul>"
html += "<h2>Licences</h2>"
html += "<p>Number of licences: " + str(len(licences)) + "</p>"
html += "<h2><a href='/admin'>Admin</a></h2>"
return html
# Admin page # Admin page
@app.route('/admin') @app.route('/admin')
@ -698,7 +641,7 @@ def addsite():
if domain.startswith("http://") or domain.startswith("https://"): if domain.startswith("http://") or domain.startswith("https://"):
return jsonify({'error': 'Domain should not contain http:// or https://', 'success': 'false'}) return jsonify({'error': 'Domain should not contain http:// or https://', 'success': 'false'})
domain = domain.lower()
# Check if worker file exists # Check if worker file exists
workers = None workers = None
try: try:
@ -837,12 +780,8 @@ def login():
def failed_login(): def failed_login():
return "<h1>Failed login</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>" return "<h1>Failed login</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
# Assets
@app.route('/assets/<path:path>')
def send_report(path):
return send_from_directory('templates/assets', path)
# Start the server # Start the server

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

View File

@ -1,61 +0,0 @@
(function() {
"use strict"; // Start of use strict
function initParallax() {
if (!('requestAnimationFrame' in window)) return;
if (/Mobile|Android/.test(navigator.userAgent)) return;
var parallaxItems = document.querySelectorAll('[data-bss-parallax]');
if (!parallaxItems.length) return;
var defaultSpeed = 0.5;
var visible = [];
var scheduled;
window.addEventListener('scroll', scroll);
window.addEventListener('resize', scroll);
scroll();
function scroll() {
visible.length = 0;
for (var i = 0; i < parallaxItems.length; i++) {
var rect = parallaxItems[i].getBoundingClientRect();
var speed = parseFloat(parallaxItems[i].getAttribute('data-bss-parallax-speed'), 10) || defaultSpeed;
if (rect.bottom > 0 && rect.top < window.innerHeight) {
visible.push({
speed: speed,
node: parallaxItems[i]
});
}
}
cancelAnimationFrame(scheduled);
if (visible.length) {
scheduled = requestAnimationFrame(update);
}
}
function update() {
for (var i = 0; i < visible.length; i++) {
var node = visible[i].node;
var speed = visible[i].speed;
node.style.transform = 'translate3d(0, ' + (-window.scrollY * speed) + 'px, 0)';
}
}
}
initParallax();
})(); // End of use strict

View File

@ -1,12 +0,0 @@
// Wait for 10 seconds
setTimeout(function() {
// Get the 'domain' parameter from the current URL
var urlParams = new URLSearchParams(window.location.search);
var domain = urlParams.get('domain');
// Construct the new URL with the 'domain' parameter
var newURL = "https://hnshosting.au/info?domain=" + domain;
// Redirect to the new URL
window.location.href = newURL;
}, 10000);

View File

@ -1,173 +0,0 @@
<!DOCTYPE html>
<html data-bs-theme="dark" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Home - HNSHosting</title>
<link rel="canonical" href="https://wp.hnshosting.au/">
<meta property="og:url" content="https://wp.hnshosting.au/">
<meta name="description" content="HNS Hosting Wordpress">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "WebSite",
"name": "HNSHosting",
"url": "https://wp.hnshosting.au"
}
</script>
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&amp;display=swap">
</head>
<body>
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navcol-1">
<ul class="navbar-nav mx-auto">
<li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
<li class="nav-item"><a class="nav-link active" href="/#contact">Contact</a></li>
<li class="nav-item"><a class="nav-link" href="register">Register Site</a></li>
</ul>
</div>
</div>
</nav>
<header class="bg-dark">
<div class="container pt-4 pt-xl-5">
<div class="row pt-5">
<div class="col-md-8 col-xl-6 text-center text-md-start mx-auto">
<div class="text-center">
<h1 class="fw-bold">The best solution for your Handshake domain</h1>
</div>
<p class="text-center" style="padding-bottom: 50px;padding-top: 25px;">Wordpress allows you to have an easily customizable website on your Handshake domain.</p>
<p class="text-center" style="font-size: 22px;">Currently hosting {{site_count}} sites!</p>
</div>
</div>
</div>
</header>
<section style="background: rgb(39,38,46);">
<div class="container bg-dark py-5" style="background: rgb(39, 38, 46);">
<div class="row">
<div class="col-md-8 col-xl-6 text-center mx-auto">
<p class="fw-bold text-success mb-2">Our Services</p>
<h3 class="fw-bold">What we do for you</h3>
</div>
</div>
<div class="py-5 p-lg-5">
<div class="row row-cols-1 row-cols-md-2 mx-auto" style="max-width: 900px;">
<div class="col mb-5">
<div class="card shadow-sm">
<div class="card-body px-4 py-5 px-md-5">
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-shield-lock text-success">
<path d="M5.338 1.59a61.44 61.44 0 0 0-2.837.856.481.481 0 0 0-.328.39c-.554 4.157.726 7.19 2.253 9.188a10.725 10.725 0 0 0 2.287 2.233c.346.244.652.42.893.533.12.057.218.095.293.118a.55.55 0 0 0 .101.025.615.615 0 0 0 .1-.025c.076-.023.174-.061.294-.118.24-.113.547-.29.893-.533a10.726 10.726 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067c-.53 0-1.552.223-2.662.524zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.775 11.775 0 0 1-2.517 2.453 7.159 7.159 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7.158 7.158 0 0 1-1.048-.625 11.777 11.777 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 62.456 62.456 0 0 1 5.072.56z"></path>
<path d="M9.5 6.5a1.5 1.5 0 0 1-1 1.415l.385 1.99a.5.5 0 0 1-.491.595h-.788a.5.5 0 0 1-.49-.595l.384-1.99a1.5 1.5 0 1 1 2-1.415z"></path>
</svg></div>
<h5 class="fw-bold card-title">Secured over SSL with DANE</h5>
<p class="text-muted card-text mb-4">Anyone with a resolver supporting DANE will be redirected to the HTTPS version on your site and will have an encrypted connection using DANE for verification.</p><a class="btn btn-primary shadow" role="button" target="_blank" href="https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities">Learn more</a>
</div>
</div>
</div>
<div class="col mb-5" style="margin-top: 150px;">
<div class="card shadow-sm">
<div class="card-body px-4 py-5 px-md-5">
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-building-lock text-success">
<path d="M2 1a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6.5a.5.5 0 0 1-1 0V1H3v14h3v-2.5a.5.5 0 0 1 .5-.5H8v4H3a1 1 0 0 1-1-1V1Z"></path>
<path d="M4.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1Zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1Zm3.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1ZM4 5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1ZM7.5 5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1Zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1ZM4.5 8a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1Zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1ZM9 13a1 1 0 0 1 1-1v-1a2 2 0 1 1 4 0v1a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1v-2Zm3-3a1 1 0 0 0-1 1v1h2v-1a1 1 0 0 0-1-1Z"></path>
</svg></div>
<h5 class="fw-bold card-title">Hosted with security in mind</h5>
<p class="text-muted card-text mb-4">The worker servers are fully secured so that the only access is HTTP for web traffic.<br>Any terminal access for maintenance is over a VPN tunnel to stop any unauthorized access. All SSH connections send a push notification to the admin's phone to alert him to any access.</p>
</div>
</div>
</div>
<div class="col mb-4" style="margin-top: -150px;">
<div class="card shadow-sm">
<div class="card-body px-4 py-5 px-md-5">
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 24 24" width="1em" fill="currentColor" class="text-success">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path>
</svg></div>
<h5 class="fw-bold card-title">Regular backups</h5>
<p class="text-muted card-text mb-4">The worker server has regular encrypted backups to an offsite location to allow recovery of any data if the server goes down.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section>
<div class="container py-5">
<div class="mx-auto" style="max-width: 900px;">
<div class="row row-cols-1 row-cols-md-2 d-flex justify-content-center">
<div class="col mb-4">
<div class="card bg-primary-light">
<div class="card-body text-center px-4 py-5 px-md-5">
<p class="fw-bold text-primary card-text mb-2">Fully Managed</p>
<h5 class="fw-bold card-title mb-3">Control over plugins, users, access and everything with your site.</h5>
</div>
</div>
</div>
<div class="col mb-4">
<div class="card bg-secondary-light">
<div class="card-body text-center px-4 py-5 px-md-5">
<p class="fw-bold text-secondary card-text mb-2">Free Licences</p>
<h5 class="fw-bold card-title mb-3">We offer a free tier with 1 GB storage capacity.<br>If you would like more please contact us to find an acceptable price for you.<br>Join our Discord for a free licence</h5>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="contact" class="py-5">
<div class="container">
<div class="row mb-5">
<div class="col-md-8 col-xl-6 text-center mx-auto">
<p class="fw-bold text-success mb-2">Contacts</p>
<h2 class="fw-bold">Contact Us</h2>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start">
<div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100">
<div class="d-flex align-items-center p-3">
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-discord">
<path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612Zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612Z"></path>
</svg></div>
<div class="px-2">
<h6 class="fw-bold mb-0">Discord</h6>
<p class="text-muted mb-0"><a href="https://l.woodburn.au/discord" target="_blank">Join our server</a></p>
</div>
</div>
<div class="d-flex align-items-center p-3">
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-envelope">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z"></path>
</svg></div>
<div class="px-2">
<h6 class="fw-bold mb-0">Email</h6>
<p class="text-muted mb-0"><a href="mailto:hosting@nathan.woodburn.au">hosting@nathan.woodburn.au</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<footer class="bg-dark">
<div class="container py-4 py-lg-5">
<hr>
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
<p class="mb-0">Copyright © 2023 HNSHosting</p>
</div>
</div>
</footer>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bold-and-dark.js"></script>
</body>
</html>

View File

@ -1,70 +0,0 @@
<!DOCTYPE html>
<html data-bs-theme="dark" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Sign up - HNSHosting</title>
<link rel="canonical" href="https://wp.hnshosting.au/register.html">
<meta property="og:url" content="https://wp.hnshosting.au/register.html">
<meta name="description" content="HNS Hosting Wordpress">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&amp;display=swap">
</head>
<body>
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navcol-1">
<ul class="navbar-nav mx-auto">
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
<li class="nav-item"><a class="nav-link" href="register">Register Site</a></li>
</ul>
</div>
</div>
</nav>
<section class="py-5">
<div class="container py-5">
<div class="row mb-4 mb-lg-5">
<div class="col-md-8 col-xl-6 text-center mx-auto">
<p class="fw-bold text-success mb-2">Register site</p>
<h2 class="fw-bold">Get started with your Hosting here.</h2>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="card">
<div class="card-body text-center d-flex flex-column align-items-center">
<form method="post" action="/register">
<div class="mb-3"><input type="text" name="domain" placeholder="Domain"></div>
<div class="mb-3"><input type="text" placeholder="Licence Key" name="licence"></div>
<div class="mb-3">
<p style="color: rgb(255,0,0);">{{ERROR_MESSAGE}}</p><button class="btn btn-primary shadow d-block w-100" type="submit">Create site</button>
</div>
<p class="text-muted">Don't have a licence?<br><a href="{{buy_licence_link}}" target="_blank">Click here to buy one</a></p>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<footer class="bg-dark">
<div class="container py-4 py-lg-5">
<hr>
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
<p class="mb-0">Copyright © 2023 HNSHosting</p>
</div>
</div>
</footer>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bold-and-dark.js"></script>
</body>
</html>

View File

@ -1,58 +0,0 @@
<!DOCTYPE html>
<html data-bs-theme="dark" lang="en" style="height: 100%;">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Home - HNSHosting</title>
<link rel="canonical" href="https://wp.hnshosting.au/success.html">
<meta property="og:url" content="https://wp.hnshosting.au/success.html">
<meta name="description" content="HNS Hosting Wordpress">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&amp;display=swap">
</head>
<body style="height: 100%;">
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navcol-1">
<ul class="navbar-nav mx-auto">
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
<li class="nav-item"><a class="nav-link" href="register">Register Site</a></li>
</ul>
</div>
</div>
</nav>
<header class="bg-dark" style="height: 75%;">
<div class="container pt-4 pt-xl-5">
<div class="row pt-5" style="height: 100%;">
<div class="col-md-8 col-xl-6 text-center text-md-start mx-auto">
<div class="text-center">
<p class="fw-bold text-success mb-2">Success</p>
<h1 class="fw-bold">{{title| safe}}</h1>
</div>
<p class="text-center">{{message | safe}}</p>
</div>
</div>
</div>
</header>
<footer class="bg-dark">
<div class="container py-4 py-lg-5">
<hr>
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
<p class="mb-0">Copyright © 2023 HNSHosting</p>
</div>
</div>
</footer>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bold-and-dark.js"></script>
<script src="assets/js/status_update.js"></script>
</body>
</html>

View File

@ -24,21 +24,6 @@ python3 -m pip install -r requirements.txt
cp .env.example .env cp .env.example .env
chmod +x wp.sh tlsa.sh chmod +x wp.sh tlsa.sh
# Add proxy to docker
mkdir ~/.docker
echo """{
\"proxies\": {
\"default\": {
\"httpProxy\": \"http://proxy.hnsproxy.au:80\",
\"httpsProxy\": \"https://proxy.hnsproxy.au:443\",
\"noProxy\": \"localhost\"
}
}
}""" > ~/.docker/config.json
# Restart docker
sudo systemctl restart docker
# Pull docker images to save time later # Pull docker images to save time later
docker pull mysql:5.7 & docker pull mysql:5.7 &
docker pull wordpress:latest & docker pull wordpress:latest &

View File

@ -44,8 +44,8 @@ def tlsa():
tlsa_file = open('wordpress-'+domain+'/tlsa.txt', 'r') tlsa_file = open('wordpress-'+domain+'/tlsa.txt', 'r')
tlsa = tlsa_file.readlines() tlsa = tlsa_file.readlines()
tlsa_file.close() tlsa_file.close()
except FileNotFoundError as e: except FileNotFoundError:
return jsonify({'error': 'TLSA record not found', 'success': 'false', 'ex': str(e)}) return jsonify({'error': 'TLSA record not found', 'success': 'false'})
# Remove newlines # Remove newlines
tlsa = tlsa[0].strip('\n') tlsa = tlsa[0].strip('\n')

View File

@ -43,8 +43,6 @@ services:
MYSQL_DATABASE: WordPressDatabase MYSQL_DATABASE: WordPressDatabase
MYSQL_USER: WordPressUser MYSQL_USER: WordPressUser
MYSQL_PASSWORD: $MYSQL_PASSWORD MYSQL_PASSWORD: $MYSQL_PASSWORD
volumes:
- mysql:/var/lib/mysql
wordpress: wordpress:
depends_on: depends_on:
- ${DOMAIN}db - ${DOMAIN}db
@ -58,11 +56,9 @@ services:
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
WORDPRESS_DB_NAME: WordPressDatabase WORDPRESS_DB_NAME: WordPressDatabase
volumes: volumes:
- data:/var/www/html [\"./:/var/www/html\"]
volumes: volumes:
mysql: mysql: {}
data:
""" > docker-compose.yml """ > docker-compose.yml
# Start the containers # Start the containers
@ -89,12 +85,6 @@ printf "server {
sub_filter_once on; sub_filter_once on;
} }
location = /.well-known/wallets/HNS {
proxy_pass $URL;
proxy_set_header Host \$http_host;
rewrite ^(.*)$ \$1/ break;
}
listen 443 ssl; listen 443 ssl;
ssl_certificate /etc/ssl/$DOMAIN.crt; ssl_certificate /etc/ssl/$DOMAIN.crt;