Compare commits
47 Commits
feature/da
...
main
Author | SHA1 | Date | |
---|---|---|---|
9d06151ed2 | |||
63ee2aa82b | |||
49acea31ac | |||
6b855a5b29 | |||
9d57b8f858 | |||
6d9ba77568 | |||
9c5b00433f | |||
e241f6ffeb | |||
188334c850 | |||
6ea4e72e8a | |||
56c7fcd617 | |||
c9f8a8237d | |||
bda99dbf5f | |||
08f36a7a50 | |||
94ebacd84d | |||
6f86987901 | |||
910ce1b098 | |||
6741f8cac2 | |||
0365832e40 | |||
40515700d1 | |||
c130bfed69 | |||
d19a121005 | |||
d0ff839ff4 | |||
8f5f8df0aa | |||
9469f23f50 | |||
639dc9065c | |||
5b5dbd6660 | |||
95aa476c64 | |||
79a8e092eb | |||
8ab4ed574f | |||
58bce1e8bf | |||
75b4f979e3 | |||
c837d5d528 | |||
a8e2d90dc6 | |||
494a7e28a6 | |||
076303d475 | |||
ac054156ef | |||
2bc34c1aca | |||
490176ab04 | |||
01b4ee9fd5 | |||
1bafb844f2 | |||
f23f361ceb | |||
7729ea62b3 | |||
457a57739a | |||
fca523f013 | |||
4482f85ded | |||
cd598cce47 |
@ -10,7 +10,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build Master:
|
Build Master:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [ubuntu-latest, arm]
|
||||||
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
|
runs-on: [ubuntu-latest, arm]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build Master:
|
Build Master:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [ubuntu-latest,arm]
|
||||||
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
|
runs-on: [ubuntu-latest,arm]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
13
README.md
@ -115,4 +115,15 @@ 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
|
BIN
assets/hns-wallet-plugin.zip
Normal file
@ -51,6 +51,7 @@ 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):
|
||||||
@ -70,6 +71,14 @@ 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:
|
||||||
@ -79,12 +88,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 {domain} creating...\nI'll send you a message when it's ready")
|
await ctx.response.send_message(f"Site https://{domain} creating...\nI'll send you a message when it's ready")
|
||||||
|
|
||||||
ready = False
|
ready = False
|
||||||
while ready == False:
|
while ready == False:
|
||||||
@ -95,7 +104,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 {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 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}`")
|
||||||
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'])
|
||||||
|
|
||||||
@ -104,6 +113,7 @@ 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")
|
||||||
@ -128,6 +138,17 @@ 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
|
||||||
@ -135,6 +156,9 @@ 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)
|
10
master/assets/css/index.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
html {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
BIN
master/assets/img/favicon.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
221
master/main.py
@ -1,4 +1,4 @@
|
|||||||
from flask import Flask, make_response, redirect, request, jsonify
|
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory
|
||||||
import dotenv
|
import dotenv
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
@ -206,6 +206,7 @@ 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'})
|
||||||
|
|
||||||
@ -232,39 +233,10 @@ 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'})
|
||||||
|
|
||||||
@ -305,7 +277,14 @@ 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
|
||||||
@ -329,7 +308,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 api.\n\n"\
|
+"You can redeem this key via the discord bot or at https://hnshosting.au/register\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)
|
||||||
@ -401,7 +380,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(':')[2].strip('\n')
|
ip = line.split(':')[1].strip('\n')
|
||||||
break
|
break
|
||||||
|
|
||||||
workers_file.close()
|
workers_file.close()
|
||||||
@ -419,7 +398,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(':')[1].strip('\n')
|
ip = line.split(':')[2].strip('\n')
|
||||||
break
|
break
|
||||||
|
|
||||||
workers_file.close()
|
workers_file.close()
|
||||||
@ -429,17 +408,7 @@ def workerIP(worker):
|
|||||||
# Home page
|
# Home page
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def home():
|
def home():
|
||||||
# Show stats and info
|
# Show index template
|
||||||
|
|
||||||
# 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:
|
||||||
@ -449,44 +418,132 @@ def home():
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Get licence info
|
|
||||||
licences = []
|
return render_template('index.html', site_count = str(len(sites)))
|
||||||
|
|
||||||
|
# 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:
|
||||||
licences_file = open('/data/licence_key.txt', 'r')
|
worker_file = open('/data/workers.txt', 'r')
|
||||||
licences = licences_file.readlines()
|
workers = worker_file.readlines()
|
||||||
licences_file.close()
|
worker_file.close()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
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
|
||||||
|
|
||||||
# Create html page
|
if worker == None:
|
||||||
html = "<h1>Welcome</h1><br>"
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support")
|
||||||
html += "<h2>Create a site</h2>"
|
|
||||||
html += "<form action='/add-site' method='POST'>"
|
# Delete licence key
|
||||||
html += "<p>Domain: <input type='text' name='domain'></p>"
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
html += "<p>Licence key: <input type='text' name='licence'></p>"
|
lines = key_file.readlines()
|
||||||
html += "<input type='submit' value='Create site'>"
|
key_file.close()
|
||||||
html += "</form>"
|
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')
|
||||||
|
@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')
|
||||||
@ -641,7 +698,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:
|
||||||
@ -780,10 +837,14 @@ 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
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=False, port=5000, host='0.0.0.0')
|
app.run(debug=False, port=5000, host='0.0.0.0')
|
6
master/templates/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
6
master/templates/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
BIN
master/templates/assets/img/brands/apple.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
master/templates/assets/img/brands/facebook.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
master/templates/assets/img/brands/google.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
master/templates/assets/img/brands/microsoft.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
master/templates/assets/img/brands/twitter.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
master/templates/assets/img/favicon.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
master/templates/assets/img/products/1.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
master/templates/assets/img/products/2.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
master/templates/assets/img/products/3.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
master/templates/assets/img/team/avatar2.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
master/templates/assets/img/team/avatar4.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
master/templates/assets/img/team/avatar5.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
61
master/templates/assets/js/bold-and-dark.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
(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
|
||||||
|
|
12
master/templates/assets/js/status_update.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// 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);
|
173
master/templates/index.html
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<!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&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>
|
70
master/templates/register.html
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<!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&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>
|
58
master/templates/success.html
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<!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&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>
|
@ -24,6 +24,21 @@ 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 &
|
||||||
|
@ -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:
|
except FileNotFoundError as e:
|
||||||
return jsonify({'error': 'TLSA record not found', 'success': 'false'})
|
return jsonify({'error': 'TLSA record not found', 'success': 'false', 'ex': str(e)})
|
||||||
|
|
||||||
# Remove newlines
|
# Remove newlines
|
||||||
tlsa = tlsa[0].strip('\n')
|
tlsa = tlsa[0].strip('\n')
|
||||||
|
14
worker/wp.sh
@ -43,6 +43,8 @@ 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
|
||||||
@ -56,9 +58,11 @@ services:
|
|||||||
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
|
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
|
||||||
WORDPRESS_DB_NAME: WordPressDatabase
|
WORDPRESS_DB_NAME: WordPressDatabase
|
||||||
volumes:
|
volumes:
|
||||||
[\"./:/var/www/html\"]
|
- data:/var/www/html
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql: {}
|
mysql:
|
||||||
|
data:
|
||||||
""" > docker-compose.yml
|
""" > docker-compose.yml
|
||||||
|
|
||||||
# Start the containers
|
# Start the containers
|
||||||
@ -85,6 +89,12 @@ 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;
|
||||||
|