generated from nathanwoodburn/python-webserver-template
feat: Initial version without atomic swap
All checks were successful
Build Docker / BuildImage (push) Successful in 41s
All checks were successful
Build Docker / BuildImage (push) Successful in 41s
This commit is contained in:
parent
15bf3f0b01
commit
8e4b7ab38f
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ __pycache__/
|
|||||||
.env
|
.env
|
||||||
.vs/
|
.vs/
|
||||||
.venv/
|
.venv/
|
||||||
|
data/
|
Binary file not shown.
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"domain": "woodburn43",
|
|
||||||
"description": "This is a test listing update",
|
|
||||||
"price": 100.2,
|
|
||||||
"tx": "somelonghexstring",
|
|
||||||
"updated": 1738214534
|
|
||||||
}
|
|
||||||
]
|
|
0
requests/accept.hurl
Normal file
0
requests/accept.hurl
Normal file
1
requests/getMessage.hurl
Normal file
1
requests/getMessage.hurl
Normal file
@ -0,0 +1 @@
|
|||||||
|
GET http://127.0.0.1:5000/api/v1/listing-message?domain=woodburn43&description=This%20is%20a%20test%20listing%20update&price=100.2&contact=contact%40nathan.woodburn.au
|
@ -3,5 +3,6 @@ POST http://127.0.0.1:5000/api/v1/list
|
|||||||
"domain":"woodburn43",
|
"domain":"woodburn43",
|
||||||
"price":100.2,
|
"price":100.2,
|
||||||
"description":"This is a test listing update",
|
"description":"This is a test listing update",
|
||||||
"tx":"somelonghexstring"
|
"contact":"contact@nathan.woodburn.au",
|
||||||
|
"signature":"az51SGj9/7MjQ8Xl6LNM5Mu99FwEna8LTDkckWqH+9wZ6L5YQNV3vEyQIVI1BApS7oI8efgjE+edXHkXO4o7uw=="
|
||||||
}
|
}
|
24
sales.py
24
sales.py
@ -19,7 +19,8 @@ class Listing:
|
|||||||
self.domain = ''
|
self.domain = ''
|
||||||
self.price = 0
|
self.price = 0
|
||||||
self.description = ''
|
self.description = ''
|
||||||
self.tx = ''
|
self.contact = ''
|
||||||
|
self.signature = ''
|
||||||
self.updated = -1
|
self.updated = -1
|
||||||
|
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
@ -28,16 +29,20 @@ class Listing:
|
|||||||
self.updated = int(time.time())
|
self.updated = int(time.time())
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Listing of {self.domain} for {self.price}, Description: {self.description}, Contact: {self.contact}, Signed: {self.signed}, Signature: {self.signature}, Updated: {self.updated}"
|
return f"Domain: {self.domain}\nPrice: {self.price}\nDescription: {self.description}\nContact: {self.contact}"
|
||||||
|
|
||||||
|
def getMessage(self):
|
||||||
|
return str(self).encode('utf-8').hex()
|
||||||
|
|
||||||
def toHTML(self):
|
def toHTML(self):
|
||||||
return f"""
|
return f"""
|
||||||
<div class="card">
|
<div class="card" style="margin: 10px;">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">{self.domain}/</h4>
|
<h4 class="card-title">{self.domain}/ <a style='text-decoration:none;' href="/verify/{self.domain}">✅</a></h4>
|
||||||
<h6 class="text-muted card-subtitle mb-2">{self.price} HNS</h6>
|
<h6 class="text-muted card-subtitle mb-2">{self.price} HNS</h6>
|
||||||
<p class="card-text">{self.description}</p>
|
<p class="card-text">{self.description}</p>
|
||||||
<p class="card-text">TX: <code>{self.tx}</code></p>
|
<p class="card-text">Contact: <code>{self.contact}</code></p>
|
||||||
|
<a href="/delete/{self.domain}" class="btn btn-info">Delete Listing</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
@ -47,12 +52,13 @@ class Listing:
|
|||||||
'domain': self.domain,
|
'domain': self.domain,
|
||||||
'description': self.description,
|
'description': self.description,
|
||||||
'price': self.price,
|
'price': self.price,
|
||||||
'tx': self.tx,
|
'contact': self.contact,
|
||||||
|
'signature': self.signature,
|
||||||
'updated': self.updated
|
'updated': self.updated
|
||||||
}
|
}
|
||||||
|
|
||||||
def to_dict(self):
|
def signed(self):
|
||||||
return self.toJSON()
|
return validate_signature(self.domain,self.signature,self.getMessage())
|
||||||
|
|
||||||
def txValid(self):
|
def txValid(self):
|
||||||
# TODO Validate tx is valid
|
# TODO Validate tx is valid
|
||||||
|
62
server.py
62
server.py
@ -85,6 +85,42 @@ def view(domain: str):
|
|||||||
return render_template("404.html"), 404
|
return render_template("404.html"), 404
|
||||||
return render_template("view.html", listing=listing)
|
return render_template("view.html", listing=listing)
|
||||||
|
|
||||||
|
@app.route("/list", methods=["POST"])
|
||||||
|
def list_form():
|
||||||
|
# Get form data
|
||||||
|
data = request.form
|
||||||
|
domain = data['domain']
|
||||||
|
price = data['price']
|
||||||
|
description = data['description']
|
||||||
|
contact = data['contact']
|
||||||
|
signature = data['signature']
|
||||||
|
|
||||||
|
listing = sales.Listing(domain=domain,price=price,description=description,contact=contact,signature=signature)
|
||||||
|
if not listing.signed():
|
||||||
|
return render_template("list.html", domain=domain, price=price, description=description, contact=contact, signature=signature, error="Signature is not valid")
|
||||||
|
|
||||||
|
status = sales.add_listing(listing)
|
||||||
|
if status != True:
|
||||||
|
return render_template("list.html", domain=domain, price=price, description=description, contact=contact, signature=signature, error="Failed to add listing")
|
||||||
|
return render_template("list.html", success="Successfully added listing")
|
||||||
|
|
||||||
|
@app.route("/delete/<path:domain>")
|
||||||
|
def delete_web(domain: str):
|
||||||
|
message = f"FS: {domain}"
|
||||||
|
return render_template("delete.html", domain=domain, message=message)
|
||||||
|
|
||||||
|
@app.route("/delete/<path:domain>", methods=["POST"])
|
||||||
|
def delete_form(domain:str):
|
||||||
|
data = request.form
|
||||||
|
signature = data['signature']
|
||||||
|
|
||||||
|
|
||||||
|
if not sales.validate_cancel_signature(domain,signature):
|
||||||
|
return render_template("delete.html", domain=domain, error="Invalid signature")
|
||||||
|
|
||||||
|
sales.remove_listing(domain)
|
||||||
|
return redirect("/")
|
||||||
|
|
||||||
@app.route("/view/<path:domain>", methods=["POST"])
|
@app.route("/view/<path:domain>", methods=["POST"])
|
||||||
def post_offer(domain: str):
|
def post_offer(domain: str):
|
||||||
data = request.form
|
data = request.form
|
||||||
@ -101,24 +137,46 @@ def report(domain: str):
|
|||||||
return render_template("404.html"), 404
|
return render_template("404.html"), 404
|
||||||
return redirect("https://l.woodburn.au/contact")
|
return redirect("https://l.woodburn.au/contact")
|
||||||
|
|
||||||
|
@app.route("/verify/<path:domain>")
|
||||||
|
def verify(domain: str):
|
||||||
|
listing = sales.search_listings(domain)
|
||||||
|
if not listing:
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
return render_template("verify.html", domain=domain, string=str(listing).replace('\n','<br>'), message=listing.getMessage(), signature=listing.signature)
|
||||||
|
|
||||||
#region API Routes
|
#region API Routes
|
||||||
def validate_data(data,required):
|
def validate_data(data,required):
|
||||||
for key in required:
|
for key in required:
|
||||||
if key not in data:
|
if key not in data:
|
||||||
return jsonify({'error': f'Missing {key}','success': False})
|
return jsonify({'error': f'Missing {key}','success': False}),400
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@app.route("/api/v1/listing-message", methods=["GET"])
|
||||||
|
def listingMessage():
|
||||||
|
# Create listing
|
||||||
|
valid = validate_data(request.args,['domain','description','price','contact'])
|
||||||
|
if valid != True:
|
||||||
|
return valid
|
||||||
|
|
||||||
|
listing = sales.Listing(**request.args)
|
||||||
|
return {
|
||||||
|
'message': listing.getMessage(),
|
||||||
|
'success': True
|
||||||
|
}
|
||||||
|
|
||||||
@app.route("/api/v1/list", methods=["POST"])
|
@app.route("/api/v1/list", methods=["POST"])
|
||||||
def list():
|
def list():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
# Validate data has domain,description,price,contact
|
# Validate data has domain,description,price,contact
|
||||||
valid = validate_data(data,['domain','description','price','tx'])
|
valid = validate_data(data,['domain','description','price','contact'])
|
||||||
if valid != True:
|
if valid != True:
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
listing = sales.Listing(**data)
|
listing = sales.Listing(**data)
|
||||||
|
if not listing.signed():
|
||||||
|
return jsonify({'error': 'Not signed','success': False,'message': f'Sign this message to post listing: {listing.getMessage()}'})
|
||||||
|
|
||||||
status = sales.add_listing(listing)
|
status = sales.add_listing(listing)
|
||||||
if status != True:
|
if status != True:
|
||||||
return jsonify({'error': 'Failed to add listing','success': False,'message': status})
|
return jsonify({'error': 'Failed to add listing','success': False,'message': status})
|
||||||
|
63
templates/delete.html
Normal file
63
templates/delete.html
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<!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>FireSales</title>
|
||||||
|
<meta name="twitter:description" content="Self Custodial Domain listings">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:image" content="/assets/img/favicon.png">
|
||||||
|
<meta name="twitter:title" content="FireSales">
|
||||||
|
<meta name="description" content="Self Custodial Domain listings">
|
||||||
|
<meta property="og:image" content="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap">
|
||||||
|
<link rel="stylesheet" href="/assets/css/Navbar-Right-Links-Dark-icons.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-5">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/list">List</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="py-4 py-xl-5">
|
||||||
|
<div class="container h-100">
|
||||||
|
<div class="row h-100">
|
||||||
|
<div class="col-md-10 col-xl-8 text-center d-flex d-sm-flex d-md-flex justify-content-center align-items-center mx-auto justify-content-md-start align-items-md-center justify-content-xl-center">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-uppercase fw-bold mb-3">FireSales</h2>
|
||||||
|
<p class="mb-4">Self custodial domain sales</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-center">{{error}}</h1>
|
||||||
|
<h1 class="text-center">{{success}}</h1>
|
||||||
|
</section>
|
||||||
|
<section style="margin: 10px;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="text-center mb-4">Delete listing for {{domain}}</h2>
|
||||||
|
<h3>Message to sign: <code>{{message}}</code></h3>
|
||||||
|
<form method="post">
|
||||||
|
<div class="d-xl-flex align-items-xl-center mb-3"><input class="form-control" type="text" id="signature" placeholder="Signature" required="" name="signature" value="{{signature}}"></div>
|
||||||
|
<div><button class="btn btn-primary d-block w-100" type="submit">Delete</button></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -20,10 +20,11 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="#"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
<div class="collapse navbar-collapse" id="navcol-5">
|
<div class="collapse navbar-collapse" id="navcol-5">
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
|
<li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/list">List</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
92
templates/list.html
Normal file
92
templates/list.html
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<!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>FireSales</title>
|
||||||
|
<meta name="twitter:description" content="Self Custodial Domain listings">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:image" content="/assets/img/favicon.png">
|
||||||
|
<meta name="twitter:title" content="FireSales">
|
||||||
|
<meta name="description" content="Self Custodial Domain listings">
|
||||||
|
<meta property="og:image" content="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap">
|
||||||
|
<link rel="stylesheet" href="/assets/css/Navbar-Right-Links-Dark-icons.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-5">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="/list">List</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="py-4 py-xl-5">
|
||||||
|
<div class="container h-100">
|
||||||
|
<div class="row h-100">
|
||||||
|
<div class="col-md-10 col-xl-8 text-center d-flex d-sm-flex d-md-flex justify-content-center align-items-center mx-auto justify-content-md-start align-items-md-center justify-content-xl-center">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-uppercase fw-bold mb-3">FireSales</h2>
|
||||||
|
<p class="mb-4">Self custodial domain sales</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-center">{{error}}</h1>
|
||||||
|
<h1 class="text-center">{{success}}</h1>
|
||||||
|
</section>
|
||||||
|
<section style="margin: 10px;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="text-center mb-4">List a domain</h2>
|
||||||
|
<form method="post">
|
||||||
|
<div class="mb-3"><input class="form-control" type="text" id="domain" name="domain" placeholder="Domain Name" required="" value="{{domain}}"></div>
|
||||||
|
<div class="mb-3"><input class="form-control" type="number" id="price" name="price" placeholder="Price" min="0" required="" value="{{price}}"></div>
|
||||||
|
<div class="mb-3"><input class="form-control" type="text" id="contact" name="contact" placeholder="Contact Info" required="" value="{{contact}}"></div>
|
||||||
|
<div class="mb-3"><textarea class="form-control" id="description" name="description" rows="6" placeholder="Description" required="">{{description}}</textarea></div>
|
||||||
|
<div class="d-xl-flex align-items-xl-center mb-3"><input class="form-control" type="text" id="signature" placeholder="Signature" required="" name="signature" value="{{signature}}" style="display: inline-block;width: auto;margin: 10px;min-width: 500px;"><button class="btn btn-primary" id="getmessage" type="button" style="display: inline-block;width: auto;margin: 10px;">Copy Message to sign</button><script>
|
||||||
|
document.getElementById("getmessage").addEventListener("click", async function() {
|
||||||
|
try {
|
||||||
|
const domain = document.getElementById("domain").value;
|
||||||
|
const description = document.getElementById("description").value;
|
||||||
|
const price = document.getElementById("price").value;
|
||||||
|
const contact = document.getElementById("contact").value;
|
||||||
|
|
||||||
|
const response = await fetch("/api/v1/listing-message?domain=" + domain + "&description=" + description + "&price=" + price + "&contact=" + contact);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
// Copy to clipboard
|
||||||
|
navigator.clipboard.writeText(result.message).then(() => {
|
||||||
|
console.log("Message copied to clipboard");
|
||||||
|
}).catch(err => {
|
||||||
|
console.error("Error copying message:", err);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching message:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script></div>
|
||||||
|
<div><button class="btn btn-primary d-block w-100" type="submit">List</button></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
57
templates/verify.html
Normal file
57
templates/verify.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<!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>FireSales</title>
|
||||||
|
<meta name="twitter:description" content="Self Custodial Domain listings">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:image" content="/assets/img/favicon.png">
|
||||||
|
<meta name="twitter:title" content="FireSales">
|
||||||
|
<meta name="description" content="Self Custodial Domain listings">
|
||||||
|
<meta property="og:image" content="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap">
|
||||||
|
<link rel="stylesheet" href="/assets/css/Navbar-Right-Links-Dark-icons.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-5">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/list">List</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="py-4 py-xl-5">
|
||||||
|
<div class="container h-100">
|
||||||
|
<div class="row h-100">
|
||||||
|
<div class="col-md-10 col-xl-8 text-center d-flex d-sm-flex d-md-flex justify-content-center align-items-center mx-auto justify-content-md-start align-items-md-center justify-content-xl-center">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-uppercase fw-bold mb-3">FireSales</h2>
|
||||||
|
<p class="mb-4">Self custodial domain sales</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section style="margin: 10px;">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="card-title">{{domain}}/</h4>
|
||||||
|
<p class="card-text">Plain Text string:<br><code>{{string|safe}}</code><br><br><br>Encoded message: <code>{{message}}</code><br>Message signature: <code>{{signature}}</code><br><br>JSON format:<br><code>{<br>"domain":"{{domain}}",<br>"message":"{{message}}",<br>"signature":"{{signature}}"<br>}</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -20,10 +20,11 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="#"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="64px"><span style="margin: 10px;">FireSales</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
<div class="collapse navbar-collapse" id="navcol-5">
|
<div class="collapse navbar-collapse" id="navcol-5">
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/list">List</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
<li class="nav-item"><a class="nav-link" href="/docs">Docs</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
<li class="nav-item"><a class="nav-link" href="/plugin">FireWallet Plugin</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user