Compare commits
27 Commits
2d68de54ac
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
f4d937ff0f
|
|||
|
3d00eef43c
|
|||
|
823b348248
|
|||
|
4adf82be49
|
|||
|
67840e04e5
|
|||
|
35628bdacf
|
|||
|
4e613b8c27
|
|||
|
2e307f90da
|
|||
|
4e8ca03aed
|
|||
|
9604f08c4e
|
|||
|
a400586b05
|
|||
|
0a47dd7cbe
|
|||
|
2b744a7cf8
|
|||
|
e60ae30668
|
|||
|
96afc29328
|
|||
|
9c0534ee2f
|
|||
|
a271ce9793
|
|||
|
6e2f4bd814
|
|||
|
30c723cebb
|
|||
|
5e6af2bcc8
|
|||
|
93f45eec12
|
|||
|
7bb07dbb9e
|
|||
|
27af90fcc6
|
|||
|
3b7c587e54
|
|||
|
aa2e5a1c4d
|
|||
|
784455fe1d
|
|||
|
7c3d101782
|
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
local=true
|
||||
admin_ip=127.0.0.1
|
||||
cookie=s%3A...
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@
|
||||
__pycache__/
|
||||
|
||||
gifts.json
|
||||
.venv/
|
||||
|
||||
27
README.md
27
README.md
@@ -1 +1,26 @@
|
||||
# faucet
|
||||
# Woodburn Faucet
|
||||
A simple faucet for Handshake domains
|
||||
|
||||
Running on [faucet.woodburn.au](https://faucet.woodburn.au)
|
||||
|
||||
## Docker deployment
|
||||
```
|
||||
docker run -d \
|
||||
--name=faucet \
|
||||
-e admin_ip=<your-IP> \
|
||||
-e cookie=<your-nb-main-cookie>
|
||||
-p 5000:5000 \
|
||||
git.woodburn.au/nathanwoodburn/faucet:latest
|
||||
|
||||
```
|
||||
|
||||
## Optional environment variables
|
||||
| Variable | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| admin_ip | IP address to allow multiple gifts sent to |
|
||||
| cookie | Cookie to use for nb-main |
|
||||
| max_price | Maximum price to pay for a domain (in HNS) | 5 |
|
||||
| max_gifts_per_interval | Maximum number of gifts to send per interval | 24 |
|
||||
| interval | Interval to send gifts (in seconds) | 86400 (24 hours) |
|
||||
| discord_webhook | Discord webhook to send notifications to | None |
|
||||
| api_key | API key for api gifts | None |
|
||||
115
gift.py
115
gift.py
@@ -14,11 +14,38 @@ cookies = {"namebase-main": nbcookie}
|
||||
nb_endpoint = "https://www.namebase.io/"
|
||||
|
||||
max_price = 5 # Max price to buy a domain at (in HNS)
|
||||
previous_gifts = []
|
||||
max_gifts_per_interval = 24 # Max gifts per interval
|
||||
interval = 60*60*24 # 24 hours
|
||||
EXPIRY_THRESHOLD = 144 * 35 # 35 days
|
||||
|
||||
if os.getenv('max_price') == 'true':
|
||||
max_price = int(os.getenv('max_price'))
|
||||
if os.getenv('max_gifts_per_interval') == 'true':
|
||||
max_gifts_per_interval = int(os.getenv('max_gifts_per_interval'))
|
||||
if os.getenv('interval') == 'true':
|
||||
interval = int(os.getenv('interval'))
|
||||
|
||||
def gift(name,email,referer, ip):
|
||||
ONLY_API = False
|
||||
if os.getenv("ONLY_API") == 'true':
|
||||
ONLY_API = True
|
||||
|
||||
def gift(name,email,referer, ip,api=False):
|
||||
global loaded
|
||||
global gifts
|
||||
global previous_gifts
|
||||
|
||||
|
||||
if ONLY_API and not api:
|
||||
return "Sorry, the faucet is currently only available through the Discord bot<br>Check back in a few minutes or contact Nathan.Woodburn/"
|
||||
|
||||
recent_gifts = 0
|
||||
for gift in previous_gifts:
|
||||
if gift['time'] > time.time() - interval:
|
||||
recent_gifts += 1
|
||||
|
||||
if recent_gifts > max_gifts_per_interval and ip != os.getenv('admin_ip'):
|
||||
return "Too many gifts recently<br>Check back in a few minutes"
|
||||
|
||||
print("Name: " + name,flush=True)
|
||||
print("Email: " + email,flush=True)
|
||||
@@ -41,19 +68,40 @@ def gift(name,email,referer, ip):
|
||||
loaded = True
|
||||
|
||||
# Check if the user has already submitted
|
||||
if ip != os.getenv('admin_ip'):
|
||||
if ip != os.getenv('admin_ip') and not api:
|
||||
ip_first = ip.split('.')[0]
|
||||
ip_block = 0
|
||||
for gift in gifts:
|
||||
if gift['email'] == email:
|
||||
return "You have already submitted a gift request"
|
||||
if gift['ip'] == ip:
|
||||
return "You have already submitted a gift request"
|
||||
|
||||
if gift['ip'].startswith(ip_first):
|
||||
if 'time' in gift and gift['time'] > (time.time() - interval*4):
|
||||
ip_block += 1
|
||||
if 'time' not in gift:
|
||||
ip_block += 1
|
||||
|
||||
if ip_block > 2:
|
||||
return "You have been rate limited<br>Contact Nathan.Woodburn if you think this is a mistake"
|
||||
|
||||
if api:
|
||||
for gift in gifts:
|
||||
if gift['email'] == email:
|
||||
return "You have already submitted a gift request"
|
||||
if gift['name'] == name:
|
||||
return "You have already submitted a gift request"
|
||||
# Add the user to the list
|
||||
gifts.append({
|
||||
'name': name,
|
||||
'email': email,
|
||||
'referer': referer,
|
||||
'ip': ip
|
||||
'ip': ip,
|
||||
'time': time.time()
|
||||
})
|
||||
|
||||
previous_gifts.append({
|
||||
'time': time.time()
|
||||
})
|
||||
|
||||
# Save the file
|
||||
@@ -69,8 +117,15 @@ def gift(name,email,referer, ip):
|
||||
if names.status_code != 200:
|
||||
return "Error getting names:<br>" + names.text
|
||||
|
||||
names = names.json()
|
||||
if len(names['domains']) == 0:
|
||||
tmpnames = names.json()
|
||||
domain = None
|
||||
for name in tmpnames['domains']:
|
||||
if (name['expireBlock'] - tmpnames['currentHeight']) > EXPIRY_THRESHOLD:
|
||||
domain = name['name']
|
||||
break
|
||||
|
||||
|
||||
if domain == None:
|
||||
domains_market = requests.get(nb_endpoint + "/api/domains/marketplace?offset=0&buyNowOnly=true&sortKey=price&sortDirection=asc&exclude=%2Cnumbers%2Chyphens%2Cunderscores&maxLength=10&offersOnly=false"
|
||||
,headers=headers, cookies=cookies)
|
||||
if domains_market.status_code != 200:
|
||||
@@ -80,24 +135,33 @@ def gift(name,email,referer, ip):
|
||||
if len(domains_market['domains']) == 0:
|
||||
return "No domains available to gift<br>Check back in a few minutes"
|
||||
|
||||
domain = domains_market['domains'][0]['name']
|
||||
print("Buying: " + domain,flush=True)
|
||||
price = int(domains_market['domains'][0]['amount'])
|
||||
if price > max_price*1000000:
|
||||
return "Domain price too high<br>Check back in a few minutes"
|
||||
listing = None
|
||||
for d in domains_market['domains']:
|
||||
if int(d['amount']) > max_price*1000000:
|
||||
continue
|
||||
data = requests.post("https://www.namebase.io/api/domains/search",headers=headers,json={"domains":[d['name']]}, cookies=cookies)
|
||||
if data.status_code != 200:
|
||||
return "Error getting names:<br>" + data.text
|
||||
data = data.json()
|
||||
if data['domains'][0]['domainInfo']['name'] != d['name']:
|
||||
return "Something weird happened<br>Check back in a few minutes"
|
||||
if (data['domains'][0]['domainInfo']['expireBlock'] - data['height']) > EXPIRY_THRESHOLD:
|
||||
domain = d['name']
|
||||
listing = d['id']
|
||||
break
|
||||
|
||||
|
||||
if domain == None:
|
||||
return "No domains available to gift<br>Check back in a few minutes"
|
||||
# Buy the domain
|
||||
print("Buying: " + domain,flush=True)
|
||||
|
||||
payload = {
|
||||
"listingId": domains_market['domains'][0]['id']
|
||||
"listingId": listing
|
||||
}
|
||||
buy = requests.post(nb_endpoint + "/api/v0/marketplace/"+domain+"/buynow",headers=headers,data=json.dumps(payload), cookies=cookies)
|
||||
if buy.status_code != 200:
|
||||
return "Error buying name:<br>" + buy.text
|
||||
|
||||
|
||||
else:
|
||||
domain = names['domains'][0]['name']
|
||||
|
||||
print("Gifting: " + domain,flush=True)
|
||||
|
||||
@@ -115,6 +179,7 @@ def gift(name,email,referer, ip):
|
||||
if send_name.status_code != 200:
|
||||
return "Error sending gift:<br>" + send_name.text
|
||||
|
||||
discord(domain,email,ip,referer)
|
||||
|
||||
return True
|
||||
|
||||
@@ -127,3 +192,21 @@ def balance():
|
||||
hns_balance = user_info['hns_balance']
|
||||
hns_balance = int(hns_balance)/1000000
|
||||
return hns_balance
|
||||
|
||||
def discord(domain, email,ip,referer):
|
||||
url = os.getenv('discord_webhook')
|
||||
if url == None:
|
||||
return "No webhook set"
|
||||
|
||||
payload = {
|
||||
"content": "New gift request: " + domain + "\nSent to " + email + "\nIP: " + ip + "\nReferer: " + referer
|
||||
}
|
||||
response = requests.post(url, data=json.dumps(payload), headers={'Content-Type': 'application/json'})
|
||||
|
||||
# Check if the message was sent successfully
|
||||
if response.status_code == 204:
|
||||
print("Message sent successfully!")
|
||||
else:
|
||||
print(f"Failed to send message. Status code: {response.status_code}")
|
||||
print(response.text)
|
||||
|
||||
|
||||
225
main.py
225
main.py
@@ -1,110 +1,219 @@
|
||||
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory
|
||||
from flask import (
|
||||
Flask,
|
||||
make_response,
|
||||
redirect,
|
||||
request,
|
||||
jsonify,
|
||||
render_template,
|
||||
send_from_directory,
|
||||
)
|
||||
import os
|
||||
import dotenv
|
||||
import requests
|
||||
import gift
|
||||
import json
|
||||
import schedule
|
||||
import time
|
||||
from email_validator import validate_email, EmailNotValidError
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
dotenv.load_dotenv()
|
||||
address = 'hs1qr7d0xqsyatls47jf28gvm97twe8k606gspfpsz'
|
||||
address = "hs1qr7d0xqsyatls47jf28gvm97twe8k606gspfpsz"
|
||||
|
||||
if os.getenv('address') != None:
|
||||
address = os.getenv('address')
|
||||
if os.getenv("address") != None:
|
||||
address = os.getenv("address")
|
||||
|
||||
#Assets routes
|
||||
@app.route('/assets/<path:path>')
|
||||
|
||||
# Assets routes
|
||||
@app.route("/assets/<path:path>")
|
||||
def send_report(path):
|
||||
return send_from_directory('templates/assets', path)
|
||||
return send_from_directory("templates/assets", path)
|
||||
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@app.route("/")
|
||||
def index():
|
||||
params = request.args
|
||||
if 'r' in params:
|
||||
print("Referer: " + params['r'])
|
||||
return render_template('index.html', hidden=params['r'],address=address)
|
||||
if "r" in request.cookies:
|
||||
print("Referer: " + request.cookies["r"])
|
||||
return render_template(
|
||||
"index.html", hidden=request.cookies["r"], address=address
|
||||
)
|
||||
|
||||
return render_template('index.html',address=address)
|
||||
if "r" in params:
|
||||
print("Referer: " + params["r"])
|
||||
# Set cookie
|
||||
resp = make_response(
|
||||
render_template("index.html", hidden=params["r"], address=address)
|
||||
)
|
||||
resp.set_cookie("r", params["r"], max_age=60 * 60 * 24)
|
||||
return resp
|
||||
return render_template("index.html", address=address)
|
||||
|
||||
|
||||
@app.route('/', methods=['POST'])
|
||||
@app.route("/", methods=["POST"])
|
||||
def submit():
|
||||
name = request.form['name']
|
||||
email = request.form['email']
|
||||
hidden = request.form['hi']
|
||||
name = request.form["name"]
|
||||
email = request.form["email"]
|
||||
hidden = request.form["hi"]
|
||||
ip = request.remote_addr
|
||||
|
||||
if 'X-REAL-IP' in request.headers:
|
||||
ip = request.headers['X-REAL-IP']
|
||||
if "X-REAL-IP" in request.headers:
|
||||
ip = request.headers["X-REAL-IP"]
|
||||
|
||||
if 'X-Real-Ip' in request.headers:
|
||||
ip = request.headers['X-Real-Ip']
|
||||
if "X-Real-Ip" in request.headers:
|
||||
ip = request.headers["X-Real-Ip"]
|
||||
|
||||
if hidden == '':
|
||||
hidden = 'None'
|
||||
if hidden == "":
|
||||
hidden = "None"
|
||||
|
||||
if "r" in request.cookies:
|
||||
hidden = request.cookies["r"]
|
||||
|
||||
# Validate email
|
||||
try:
|
||||
emailinfo = validate_email(email, check_deliverability=False)
|
||||
email = emailinfo.normalized
|
||||
except EmailNotValidError as e:
|
||||
return render_template(
|
||||
"error.html", error="Invalid email address", address=address
|
||||
)
|
||||
|
||||
status = gift.gift(name, email, hidden, ip)
|
||||
print(status,flush=True)
|
||||
print(status, flush=True)
|
||||
|
||||
if status == True:
|
||||
return render_template('success.html',address=address)
|
||||
return render_template("success.html", address=address)
|
||||
else:
|
||||
return render_template('error.html',error=status,address=address)
|
||||
return render_template("error.html", error=status, address=address)
|
||||
|
||||
|
||||
@app.route("/api", methods=["POST"])
|
||||
def api():
|
||||
# Get from params
|
||||
params = request.args
|
||||
name = params["name"]
|
||||
email = params["email"]
|
||||
key = params["key"]
|
||||
|
||||
if key != os.getenv("api_key"):
|
||||
return jsonify({"error": "Invalid API key", "success": False})
|
||||
|
||||
if "X-REAL-IP" in request.headers:
|
||||
ip = request.headers["X-REAL-IP"]
|
||||
|
||||
if "X-Real-Ip" in request.headers:
|
||||
ip = request.headers["X-Real-Ip"]
|
||||
|
||||
# Validate email
|
||||
try:
|
||||
emailinfo = validate_email(email, check_deliverability=False)
|
||||
email = emailinfo.normalized
|
||||
except EmailNotValidError as e:
|
||||
return jsonify({"error": "Invalid email address", "success": False})
|
||||
|
||||
status = gift.gift(name, email, "api", ip, True)
|
||||
print(status, flush=True)
|
||||
|
||||
if status == True:
|
||||
return jsonify({"success": True})
|
||||
else:
|
||||
return jsonify({"error": status, "success": False})
|
||||
|
||||
|
||||
# Special routes
|
||||
@app.route('/.well-known/wallets/<token>')
|
||||
@app.route("/.well-known/wallets/<token>")
|
||||
def send_wallet(token):
|
||||
address = requests.get('https://nathan.woodburn.au/.well-known/wallets/'+token).text
|
||||
return make_response(address, 200, {'Content-Type': 'text/plain'})
|
||||
address = requests.get(
|
||||
"https://nathan.woodburn.au/.well-known/wallets/" + token
|
||||
).text
|
||||
return make_response(address, 200, {"Content-Type": "text/plain"})
|
||||
|
||||
@app.route('/stats')
|
||||
|
||||
@app.route("/stats")
|
||||
def stats():
|
||||
# Read the file
|
||||
path = '/data/gifts.json'
|
||||
if os.getenv('local') == 'true':
|
||||
path = './gifts.json'
|
||||
path = "/data/gifts.json"
|
||||
if os.getenv("local") == "true":
|
||||
path = "./gifts.json"
|
||||
|
||||
# Load file
|
||||
gifts = []
|
||||
if os.path.isfile(path):
|
||||
with open(path, 'r') as f:
|
||||
gifts = json.load(f)
|
||||
with open(path, "r") as f:
|
||||
gifts = json.load(f)
|
||||
|
||||
# Loop through gifts
|
||||
referals = {}
|
||||
for gift_item in gifts:
|
||||
if gift_item['referer'] not in referals:
|
||||
referals[gift_item['referer']] = 1
|
||||
if gift_item["referer"] not in referals:
|
||||
referals[gift_item["referer"]] = 1
|
||||
else:
|
||||
referals[gift_item['referer']] += 1
|
||||
|
||||
statsHTML = 'Total gifts: ' + str(len(gifts)) + '<br><br>'
|
||||
statsHTML += 'Referals:<br>'
|
||||
referals[gift_item["referer"]] += 1
|
||||
|
||||
statsHTML = "Total gifts: " + str(len(gifts)) + "<br><br>"
|
||||
statsHTML += "Referals:<br>"
|
||||
for referal in referals:
|
||||
statsHTML += referal + ': ' + str(referals[referal]) + '<br>'
|
||||
statsHTML += referal + ": " + str(referals[referal]) + "<br>"
|
||||
|
||||
statsHTML += "<br>Remaining balance: " + str(gift.balance()) + " HNS<br>"
|
||||
|
||||
return render_template("stats.html", address=address, stats=statsHTML)
|
||||
|
||||
|
||||
statsHTML += '<br>Remaining HNS: ' + str(gift.balance()) + '<br>'
|
||||
|
||||
return render_template('stats.html',address=address,stats=statsHTML)
|
||||
|
||||
@app.route('/<path:path>')
|
||||
@app.route("/<path:path>")
|
||||
def catch_all(path):
|
||||
# # If file exists, load it
|
||||
# if os.path.isfile('templates/' + path):
|
||||
# return render_template(path)
|
||||
|
||||
# # Try with .html
|
||||
# if os.path.isfile('templates/' + path + '.html'):
|
||||
# return render_template(path + '.html')
|
||||
return redirect('/')
|
||||
return redirect("/?r=" + path)
|
||||
|
||||
|
||||
# 404 catch all
|
||||
@app.errorhandler(404)
|
||||
def not_found(e):
|
||||
return redirect('/')
|
||||
return redirect("/")
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=False, port=5000, host='0.0.0.0')
|
||||
|
||||
def update_address():
|
||||
global address
|
||||
payload = {
|
||||
"asset": "HNS",
|
||||
"timestamp": int(round(time.time() * 1000)),
|
||||
"receiveWindow": 20000,
|
||||
}
|
||||
nbcookie = os.getenv("cookie")
|
||||
cookies = {"namebase-main": nbcookie}
|
||||
headers = {"Accept": "application/json", "Content-Type": "application/json"}
|
||||
r = requests.post(
|
||||
"https://www.namebase.io/api/v0/deposit/address",
|
||||
data=json.dumps(payload),
|
||||
headers=headers,
|
||||
cookies=cookies,
|
||||
)
|
||||
if "address" not in r.json():
|
||||
print("Error: " + r.text, flush=True)
|
||||
# Send alert via discord
|
||||
url = os.getenv("discord_webhook")
|
||||
if url == None:
|
||||
return "No webhook set"
|
||||
|
||||
payload = {"content": "NB cookie has expired\n@everyone"}
|
||||
response = requests.post(
|
||||
url, data=json.dumps(payload), headers={"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
# Check if the message was sent successfully
|
||||
if response.status_code == 204:
|
||||
print("Message sent successfully!")
|
||||
else:
|
||||
print(f"Failed to send message. Status code: {response.status_code}")
|
||||
print(response.text)
|
||||
return
|
||||
|
||||
address = r.json()["address"]
|
||||
print("Address updated: " + address, flush=True)
|
||||
|
||||
|
||||
update_address()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=False, port=5000, host="0.0.0.0")
|
||||
|
||||
@@ -2,4 +2,8 @@ flask
|
||||
python-dotenv
|
||||
gunicorn
|
||||
requests
|
||||
pyotp
|
||||
pyotp
|
||||
schedule
|
||||
email-validator
|
||||
py3dns
|
||||
apscheduler
|
||||
@@ -7,6 +7,7 @@ import os
|
||||
import dotenv
|
||||
import sys
|
||||
import json
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
|
||||
class GunicornApp(BaseApplication):
|
||||
@@ -24,6 +25,12 @@ class GunicornApp(BaseApplication):
|
||||
return self.application
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Every hour
|
||||
scheduler = BackgroundScheduler()
|
||||
scheduler.add_job(main.update_address, 'cron', hour='0')
|
||||
scheduler.start()
|
||||
|
||||
|
||||
workers = os.getenv('WORKERS')
|
||||
threads = os.getenv('THREADS')
|
||||
if workers is None:
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -10,13 +10,13 @@
|
||||
<meta property="og:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="twitter:title" content="Woodburn Faucet">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:title" content="Woodburn Faucet">
|
||||
<meta name="twitter:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="assets/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png" media="(prefers-color-scheme: dark)">
|
||||
@@ -29,11 +29,27 @@ Claim a free Handshake domain">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||
<link rel="stylesheet" href="assets/fonts/material-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/styles.min.css">
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="https://analytics.woodburn.au/";
|
||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||
_paq.push(['setSiteId', '5']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
<script async src="https://umami.woodburn.au/script.js" data-website-id="f9357bd9-88b0-473d-9484-b1d37b1b5c87"></script>
|
||||
</head>
|
||||
|
||||
<body style="background: rgb(39,38,46);">
|
||||
<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="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a><button class="navbar-toggler" data-bs-toggle="collapse"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button></div>
|
||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a></div>
|
||||
</nav>
|
||||
<header class="bg-dark">
|
||||
<div class="container pt-4 pt-xl-5">
|
||||
@@ -54,10 +70,10 @@ Claim a free Handshake domain">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section style="margin-top: 50px;">
|
||||
<section style="margin: auto;margin-top: 50px;max-width: 90%;">
|
||||
<div style="text-align: center;">
|
||||
<h3>Donate to fund the faucet</h3>
|
||||
<h4>{{address}}</h4>
|
||||
<h4 class="text-truncate">{{address}}</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section style="background: #27262e;">
|
||||
@@ -84,7 +100,16 @@ Claim a free Handshake domain">
|
||||
<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;"><i class="material-icons text-success">dns</i></div>
|
||||
<h5 class="fw-bold card-title">Woodburn Registry</h5>
|
||||
<p class="text-muted card-text mb-4">Free Handshake compatible DNS server. Also provides free SLDs for testing</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
<p class="text-muted card-text mb-4">Free Handshake DNS service. Also provides free SLDs on select TLDs</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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;"><i class="material-icons text-success">web</i></div>
|
||||
<h5 class="fw-bold card-title">ShakeCities</h5>
|
||||
<p class="text-muted card-text mb-4">Unlock web ownership's future with ShakeCities! Create your free, secure Handshake domain site. Integrate crypto payments, explore HNSChat, and join us in shaping the decentralized web!</p><a class="btn btn-primary shadow" role="button" href="https://shakecities.com" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,7 +125,7 @@ Claim a free Handshake domain">
|
||||
<p class="w-lg-50">Thanks to these donors for supporting the faucet</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-2 row-cols-md-4">
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-2 row-cols-xl-4 row-cols-xxl-4">
|
||||
<div class="col">
|
||||
<div class="card border-0 shadow-none">
|
||||
<div class="card-body text-center d-flex flex-column align-items-center p-0"><img class="rounded-circle mb-3 fit-cover" width="130" height="130" src="assets/img/team/nathanwoodburn.webp" style="margin-top: 10px;">
|
||||
@@ -140,7 +165,7 @@ Claim a free Handshake domain">
|
||||
<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">Copyright © 2023 Nathan.Woodburn/</p>
|
||||
<p class="mb-0 copyright">Copyright © 2023 Nathan.Woodburn/</p><a href="/stats">Stats</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<meta property="og:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="twitter:title" content="Woodburn Faucet">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:title" content="Woodburn Faucet">
|
||||
<meta name="twitter:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "http://schema.org",
|
||||
@@ -37,11 +37,27 @@ Claim a free Handshake domain">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||
<link rel="stylesheet" href="assets/fonts/material-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/styles.min.css">
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="https://analytics.woodburn.au/";
|
||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||
_paq.push(['setSiteId', '5']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
<script async src="https://umami.woodburn.au/script.js" data-website-id="f9357bd9-88b0-473d-9484-b1d37b1b5c87"></script>
|
||||
</head>
|
||||
|
||||
<body style="background: rgb(39,38,46);">
|
||||
<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="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a><button class="navbar-toggler" data-bs-toggle="collapse"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button></div>
|
||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a></div>
|
||||
</nav>
|
||||
<header class="bg-dark">
|
||||
<div class="container pt-4 pt-xl-5">
|
||||
@@ -56,16 +72,16 @@ Claim a free Handshake domain">
|
||||
<div class="text-center position-relative" style="display: block;flex-wrap: wrap;justify-content: flex-end;">
|
||||
<h2 style="width: 100%;">Send a free domain to your email</h2>
|
||||
<p>Powered by <a href="https://www.namebase.io/register/kdh57i" target="_blank">Namebase</a> instant transfers</p>
|
||||
<form class="text-center" style="width: 100%;" method="post"><input class="form-control" type="text" style="margin: auto;max-width: 450px;margin-top: 10px;margin-bottom: 10px;" name="name" placeholder="Name" required="" minlength="3"><input class="form-control" type="email" style="margin: auto;max-width: 450px;margin-top: 10px;margin-bottom: 10px;" placeholder="your@email.com" name="email" required=""><input class="btn btn-primary" type="submit"><input class="form-control" type="hidden" name="hi" value="{{hidden}}"></form>
|
||||
<form class="text-center" style="width: 100%;" method="post"><input class="form-control" type="text" style="margin: auto;max-width: 450px;margin-top: 10px;margin-bottom: 10px;" name="name" placeholder="Name" required="" minlength="3"><input class="form-control" type="email" style="margin: auto;max-width: 450px;margin-top: 10px;margin-bottom: 10px;" placeholder="your@email.com" name="email" required=""><input class="btn btn-primary" type="submit" data-umami-event="Gift Button"><input class="form-control" type="hidden" name="hi" value="{{hidden}}"></form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section style="margin-top: 50px;">
|
||||
<section style="margin: auto;margin-top: 50px;max-width: 90%;">
|
||||
<div style="text-align: center;">
|
||||
<h3>Donate to fund the faucet</h3>
|
||||
<h4>{{address}}</h4>
|
||||
<h4 class="text-truncate">{{address}}</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section style="background: #27262e;">
|
||||
@@ -92,7 +108,16 @@ Claim a free Handshake domain">
|
||||
<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;"><i class="material-icons text-success">dns</i></div>
|
||||
<h5 class="fw-bold card-title">Woodburn Registry</h5>
|
||||
<p class="text-muted card-text mb-4">Free Handshake compatible DNS server. Also provides free SLDs for testing</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
<p class="text-muted card-text mb-4">Free Handshake DNS service. Also provides free SLDs on select TLDs</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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;"><i class="material-icons text-success">web</i></div>
|
||||
<h5 class="fw-bold card-title">ShakeCities</h5>
|
||||
<p class="text-muted card-text mb-4">Unlock web ownership's future with ShakeCities! Create your free, secure Handshake domain site. Integrate crypto payments, explore HNSChat, and join us in shaping the decentralized web!</p><a class="btn btn-primary shadow" role="button" href="https://shakecities.com" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,7 +133,7 @@ Claim a free Handshake domain">
|
||||
<p class="w-lg-50">Thanks to these donors for supporting the faucet</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-2 row-cols-md-4">
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-2 row-cols-xl-4 row-cols-xxl-4">
|
||||
<div class="col">
|
||||
<div class="card border-0 shadow-none">
|
||||
<div class="card-body text-center d-flex flex-column align-items-center p-0"><img class="rounded-circle mb-3 fit-cover" width="130" height="130" src="assets/img/team/nathanwoodburn.webp" style="margin-top: 10px;">
|
||||
@@ -148,7 +173,7 @@ Claim a free Handshake domain">
|
||||
<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">Copyright © 2023 Nathan.Woodburn/</p>
|
||||
<p class="mb-0 copyright">Copyright © 2025 Nathan.Woodburn/</p><a href="/stats">Stats</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<meta property="og:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="twitter:title" content="Woodburn Faucet">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:title" content="Woodburn Faucet">
|
||||
<meta name="twitter:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="assets/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png" media="(prefers-color-scheme: dark)">
|
||||
@@ -29,11 +29,27 @@ Claim a free Handshake domain">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||
<link rel="stylesheet" href="assets/fonts/material-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/styles.min.css">
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="https://analytics.woodburn.au/";
|
||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||
_paq.push(['setSiteId', '5']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
<script async src="https://umami.woodburn.au/script.js" data-website-id="f9357bd9-88b0-473d-9484-b1d37b1b5c87"></script>
|
||||
</head>
|
||||
|
||||
<body style="background: rgb(39,38,46);">
|
||||
<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="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a><button class="navbar-toggler" data-bs-toggle="collapse"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button></div>
|
||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a></div>
|
||||
</nav>
|
||||
<header class="bg-dark" style="background: rgb(39, 38, 46);">
|
||||
<div class="container pt-4 pt-xl-5">
|
||||
@@ -53,10 +69,10 @@ Claim a free Handshake domain">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section style="margin-top: 50px;">
|
||||
<section style="margin: auto;margin-top: 50px;max-width: 90%;">
|
||||
<div style="text-align: center;">
|
||||
<h3>Donate to fund the faucet</h3>
|
||||
<h4>{{address}}</h4>
|
||||
<h4 class="text-truncate">{{address}}</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section style="background: #27262e;">
|
||||
@@ -83,7 +99,16 @@ Claim a free Handshake domain">
|
||||
<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;"><i class="material-icons text-success">dns</i></div>
|
||||
<h5 class="fw-bold card-title">Woodburn Registry</h5>
|
||||
<p class="text-muted card-text mb-4">Free Handshake compatible DNS server. Also provides free SLDs for testing</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
<p class="text-muted card-text mb-4">Free Handshake DNS service. Also provides free SLDs on select TLDs</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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;"><i class="material-icons text-success">web</i></div>
|
||||
<h5 class="fw-bold card-title">ShakeCities</h5>
|
||||
<p class="text-muted card-text mb-4">Unlock web ownership's future with ShakeCities! Create your free, secure Handshake domain site. Integrate crypto payments, explore HNSChat, and join us in shaping the decentralized web!</p><a class="btn btn-primary shadow" role="button" href="https://shakecities.com" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -99,7 +124,7 @@ Claim a free Handshake domain">
|
||||
<p class="w-lg-50">Thanks to these donors for supporting the faucet</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-2 row-cols-md-4">
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-2 row-cols-xl-4 row-cols-xxl-4">
|
||||
<div class="col">
|
||||
<div class="card border-0 shadow-none">
|
||||
<div class="card-body text-center d-flex flex-column align-items-center p-0"><img class="rounded-circle mb-3 fit-cover" width="130" height="130" src="assets/img/team/nathanwoodburn.webp" style="margin-top: 10px;">
|
||||
@@ -139,7 +164,7 @@ Claim a free Handshake domain">
|
||||
<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">Copyright © 2023 Nathan.Woodburn/</p>
|
||||
<p class="mb-0 copyright">Copyright © 2025 Nathan.Woodburn/</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<meta property="og:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="twitter:title" content="Woodburn Faucet">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:title" content="Woodburn Faucet">
|
||||
<meta name="twitter:description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta name="description" content="Woodburn Faucet
|
||||
Claim a free Handshake domain">
|
||||
<meta property="og:image" content="https://faucet.woodburn.au/assets/img/android-chrome-512x512.png">
|
||||
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="assets/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png" media="(prefers-color-scheme: dark)">
|
||||
@@ -29,11 +29,27 @@ Claim a free Handshake domain">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||
<link rel="stylesheet" href="assets/fonts/material-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/styles.min.css">
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="https://analytics.woodburn.au/";
|
||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||
_paq.push(['setSiteId', '5']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
<script async src="https://umami.woodburn.au/script.js" data-website-id="f9357bd9-88b0-473d-9484-b1d37b1b5c87"></script>
|
||||
</head>
|
||||
|
||||
<body style="background: rgb(39,38,46);">
|
||||
<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="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a><button class="navbar-toggler" data-bs-toggle="collapse"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button></div>
|
||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="assets/img/favicon.svg" width="50em"><span> Woodburn Faucet</span></a></div>
|
||||
</nav>
|
||||
<header class="bg-dark" style="background: rgb(39, 38, 46);">
|
||||
<div class="container pt-4 pt-xl-5">
|
||||
@@ -53,10 +69,10 @@ Claim a free Handshake domain">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section style="margin-top: 50px;">
|
||||
<section style="margin: auto;margin-top: 50px;max-width: 90%;">
|
||||
<div style="text-align: center;">
|
||||
<h3>Donate to fund the faucet</h3>
|
||||
<h4>{{address}}</h4>
|
||||
<h4 class="text-truncate">{{address}}</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section style="background: #27262e;">
|
||||
@@ -83,7 +99,16 @@ Claim a free Handshake domain">
|
||||
<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;"><i class="material-icons text-success">dns</i></div>
|
||||
<h5 class="fw-bold card-title">Woodburn Registry</h5>
|
||||
<p class="text-muted card-text mb-4">Free Handshake compatible DNS server. Also provides free SLDs for testing</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
<p class="text-muted card-text mb-4">Free Handshake DNS service. Also provides free SLDs on select TLDs</p><a class="btn btn-primary shadow" role="button" href="https://reg.woodburn.au" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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;"><i class="material-icons text-success">web</i></div>
|
||||
<h5 class="fw-bold card-title">ShakeCities</h5>
|
||||
<p class="text-muted card-text mb-4">Unlock web ownership's future with ShakeCities! Create your free, secure Handshake domain site. Integrate crypto payments, explore HNSChat, and join us in shaping the decentralized web!</p><a class="btn btn-primary shadow" role="button" href="https://shakecities.com" target="_blank">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -99,7 +124,7 @@ Claim a free Handshake domain">
|
||||
<p class="w-lg-50">Thanks to these donors for supporting the faucet</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-2 row-cols-md-4">
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-2 row-cols-xl-4 row-cols-xxl-4">
|
||||
<div class="col">
|
||||
<div class="card border-0 shadow-none">
|
||||
<div class="card-body text-center d-flex flex-column align-items-center p-0"><img class="rounded-circle mb-3 fit-cover" width="130" height="130" src="assets/img/team/nathanwoodburn.webp" style="margin-top: 10px;">
|
||||
@@ -139,7 +164,7 @@ Claim a free Handshake domain">
|
||||
<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">Copyright © 2023 Nathan.Woodburn/</p>
|
||||
<p class="mb-0 copyright">Copyright © 2025 Nathan.Woodburn/</p><a href="/stats">Stats</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user