Compare commits
11 Commits
feat/mempo
...
5ff8960b7b
| Author | SHA1 | Date | |
|---|---|---|---|
|
5ff8960b7b
|
|||
|
4c84bc2bbe
|
|||
|
49e378803d
|
|||
|
1c53547047
|
|||
|
080c4402d8
|
|||
|
792688064e
|
|||
|
599c0df00c
|
|||
|
a619d78efd
|
|||
|
f090b7b71a
|
|||
|
545a0b9475
|
|||
|
501091eeae
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,3 +16,6 @@ customPlugins/
|
|||||||
cache/
|
cache/
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
|
hsd/
|
||||||
|
hsd-data/
|
||||||
|
hsd.lock
|
||||||
|
|||||||
Binary file not shown.
@@ -124,6 +124,8 @@ SHOW_EXPIRED: Show expired domains (true/false)
|
|||||||
EXCLUDE: Comma separated list of wallets to exclude from the wallet list (default primary)
|
EXCLUDE: Comma separated list of wallets to exclude from the wallet list (default primary)
|
||||||
EXPLORER_TX: URL for exploring transactions (default https://shakeshift.com/transaction/)
|
EXPLORER_TX: URL for exploring transactions (default https://shakeshift.com/transaction/)
|
||||||
HSD_NETWORK: Network to connect to (main, regtest, simnet)
|
HSD_NETWORK: Network to connect to (main, regtest, simnet)
|
||||||
|
DISABLE_WALLETDNS: Disable Wallet DNS records when sending HNS to domains (true/false)
|
||||||
|
INTERNAL_HSD: Use internal HSD node (true/false)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
268
account.py
268
account.py
@@ -7,22 +7,22 @@ import re
|
|||||||
import domainLookup
|
import domainLookup
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
import subprocess
|
||||||
|
import atexit
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
HSD_API = os.getenv("HSD_API")
|
HSD_API = os.getenv("HSD_API","")
|
||||||
HSD_IP = os.getenv("HSD_IP")
|
HSD_IP = os.getenv("HSD_IP","localhost")
|
||||||
if HSD_IP is None:
|
|
||||||
HSD_IP = "localhost"
|
|
||||||
|
|
||||||
HSD_NETWORK = os.getenv("HSD_NETWORK")
|
HSD_NETWORK = os.getenv("HSD_NETWORK", "main")
|
||||||
HSD_WALLET_PORT = 12039
|
HSD_WALLET_PORT = 12039
|
||||||
HSD_NODE_PORT = 12037
|
HSD_NODE_PORT = 12037
|
||||||
|
|
||||||
if not HSD_NETWORK:
|
HSD_NETWORK = HSD_NETWORK.lower()
|
||||||
HSD_NETWORK = "main"
|
|
||||||
else:
|
|
||||||
HSD_NETWORK = HSD_NETWORK.lower()
|
|
||||||
|
|
||||||
if HSD_NETWORK == "simnet":
|
if HSD_NETWORK == "simnet":
|
||||||
HSD_WALLET_PORT = 15039
|
HSD_WALLET_PORT = 15039
|
||||||
@@ -34,11 +34,33 @@ elif HSD_NETWORK == "regtest":
|
|||||||
HSD_WALLET_PORT = 14039
|
HSD_WALLET_PORT = 14039
|
||||||
HSD_NODE_PORT = 14037
|
HSD_NODE_PORT = 14037
|
||||||
|
|
||||||
|
HSD_INTERNAL_NODE = os.getenv("INTERNAL_HSD","false").lower() in ["1","true","yes"]
|
||||||
|
if HSD_INTERNAL_NODE:
|
||||||
|
if HSD_API == "":
|
||||||
|
# Use a random API KEY
|
||||||
|
HSD_API = "firewallet-" + str(int(time.time()))
|
||||||
|
HSD_IP = "localhost"
|
||||||
|
|
||||||
SHOW_EXPIRED = os.getenv("SHOW_EXPIRED")
|
SHOW_EXPIRED = os.getenv("SHOW_EXPIRED")
|
||||||
if SHOW_EXPIRED is None:
|
if SHOW_EXPIRED is None:
|
||||||
SHOW_EXPIRED = False
|
SHOW_EXPIRED = False
|
||||||
|
|
||||||
|
HSD_PROCESS = None
|
||||||
|
|
||||||
|
# Get hsdconfig.json
|
||||||
|
HSD_CONFIG = {}
|
||||||
|
if not os.path.exists('hsdconfig.json'):
|
||||||
|
# Pull from the latest git
|
||||||
|
response = requests.get("https://git.woodburn.au/nathanwoodburn/firewalletbrowser/raw/branch/main/hsdconfig.json")
|
||||||
|
if response.status_code == 200:
|
||||||
|
with open('hsdconfig.json', 'w') as f:
|
||||||
|
f.write(response.text)
|
||||||
|
HSD_CONFIG = response.json()
|
||||||
|
else:
|
||||||
|
with open('hsdconfig.json') as f:
|
||||||
|
HSD_CONFIG = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
hsd = api.hsd(HSD_API, HSD_IP, HSD_NODE_PORT)
|
hsd = api.hsd(HSD_API, HSD_IP, HSD_NODE_PORT)
|
||||||
hsw = api.hsw(HSD_API, HSD_IP, HSD_WALLET_PORT)
|
hsw = api.hsw(HSD_API, HSD_IP, HSD_WALLET_PORT)
|
||||||
|
|
||||||
@@ -47,9 +69,7 @@ cacheTime = 3600
|
|||||||
# Verify the connection
|
# Verify the connection
|
||||||
response = hsd.getInfo()
|
response = hsd.getInfo()
|
||||||
|
|
||||||
EXCLUDE = ["primary"]
|
EXCLUDE = os.getenv("EXCLUDE","primary").split(",")
|
||||||
if os.getenv("EXCLUDE") is not None:
|
|
||||||
EXCLUDE = os.getenv("EXCLUDE").split(",")
|
|
||||||
|
|
||||||
|
|
||||||
def hsdConnected():
|
def hsdConnected():
|
||||||
@@ -68,7 +88,7 @@ def hsdVersion(format=True):
|
|||||||
return info['version']
|
return info['version']
|
||||||
|
|
||||||
|
|
||||||
def check_account(cookie: str):
|
def check_account(cookie: str | None):
|
||||||
if cookie is None:
|
if cookie is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -84,7 +104,12 @@ def check_account(cookie: str):
|
|||||||
return account
|
return account
|
||||||
|
|
||||||
|
|
||||||
def check_password(cookie: str, password: str):
|
def check_password(cookie: str|None, password: str|None):
|
||||||
|
if cookie is None:
|
||||||
|
return False
|
||||||
|
if password is None:
|
||||||
|
password = ""
|
||||||
|
|
||||||
account = check_account(cookie)
|
account = check_account(cookie)
|
||||||
if account == False:
|
if account == False:
|
||||||
return False
|
return False
|
||||||
@@ -403,17 +428,34 @@ def check_hip2(domain: str):
|
|||||||
return 'Invalid domain'
|
return 'Invalid domain'
|
||||||
|
|
||||||
address = domainLookup.hip2(domain)
|
address = domainLookup.hip2(domain)
|
||||||
if address.startswith("Hip2: "):
|
if not address.startswith("Hip2: "):
|
||||||
|
if not check_address(address, False, True):
|
||||||
|
return 'Hip2: Lookup succeeded but address is invalid'
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
# Check if DISABLE_WALLETDNS is set
|
||||||
|
if os.getenv("DISABLE_WALLETDNS","").lower() in ["1","true","yes"]:
|
||||||
|
return "No HIP2 record found for this domain"
|
||||||
|
# Try using WALLET TXT record
|
||||||
|
address = domainLookup.wallet_txt(domain)
|
||||||
|
if not address.startswith("hs1"):
|
||||||
|
return "No HIP2 or WALLET record found for this domain"
|
||||||
if not check_address(address, False, True):
|
if not check_address(address, False, True):
|
||||||
return 'Hip2: Lookup succeeded but address is invalid'
|
return 'WALLET DNS record found but address is invalid'
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def send(account, address, amount):
|
def send(account, address, amount):
|
||||||
account_name = check_account(account)
|
account_name = check_account(account)
|
||||||
password = ":".join(account.split(":")[1:])
|
password = ":".join(account.split(":")[1:])
|
||||||
|
if not account_name:
|
||||||
|
return {
|
||||||
|
"error": {
|
||||||
|
"message": "Invalid account"
|
||||||
|
}
|
||||||
|
}
|
||||||
response = hsw.rpc_selectWallet(account_name)
|
response = hsw.rpc_selectWallet(account_name)
|
||||||
if response['error'] is not None:
|
if response['error'] is not None:
|
||||||
return {
|
return {
|
||||||
@@ -718,9 +760,13 @@ def getPendingFinalizes(account, password):
|
|||||||
pending = []
|
pending = []
|
||||||
try:
|
try:
|
||||||
for output in tx['outputs']:
|
for output in tx['outputs']:
|
||||||
if output['covenant']['type'] != 10:
|
if type(output) != dict:
|
||||||
continue
|
continue
|
||||||
if output['covenant']['action'] != "FINALIZE":
|
if not 'covenant' in output:
|
||||||
|
continue
|
||||||
|
if output['covenant'].get("type") != 10:
|
||||||
|
continue
|
||||||
|
if output['covenant'].get('action') != "FINALIZE":
|
||||||
continue
|
continue
|
||||||
nameHash = output['covenant']['items'][0]
|
nameHash = output['covenant']['items'][0]
|
||||||
# Try to get the name from hash
|
# Try to get the name from hash
|
||||||
@@ -1414,7 +1460,6 @@ def generateReport(account, format="{name},{expiry},{value},{maxBid}"):
|
|||||||
|
|
||||||
def convertHNS(value: int):
|
def convertHNS(value: int):
|
||||||
return value/1000000
|
return value/1000000
|
||||||
return value/1000000
|
|
||||||
|
|
||||||
|
|
||||||
def get_node_api_url(path=''):
|
def get_node_api_url(path=''):
|
||||||
@@ -1436,3 +1481,188 @@ def get_wallet_api_url(path=''):
|
|||||||
path = f'/{path}'
|
path = f'/{path}'
|
||||||
return f"{base_url}{path}"
|
return f"{base_url}{path}"
|
||||||
return base_url
|
return base_url
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# region HSD Internal Node
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def checkPreRequisites() -> dict[str, bool]:
|
||||||
|
prerequisites = {
|
||||||
|
"node": False,
|
||||||
|
"npm": False,
|
||||||
|
"git": False,
|
||||||
|
"hsd": False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if node is installed and get version
|
||||||
|
nodeSubprocess = subprocess.run(["node", "-v"], capture_output=True, text=True)
|
||||||
|
if nodeSubprocess.returncode == 0:
|
||||||
|
major_version = int(nodeSubprocess.stdout.strip().lstrip('v').split('.')[0])
|
||||||
|
if major_version >= HSD_CONFIG.get("minNodeVersion", 20):
|
||||||
|
prerequisites["node"] = True
|
||||||
|
|
||||||
|
# Check if npm is installed
|
||||||
|
npmSubprocess = subprocess.run(["npm", "-v"], capture_output=True, text=True)
|
||||||
|
if npmSubprocess.returncode == 0:
|
||||||
|
major_version = int(npmSubprocess.stdout.strip().split('.')[0])
|
||||||
|
if major_version >= HSD_CONFIG.get("minNPMVersion", 8):
|
||||||
|
prerequisites["npm"] = True
|
||||||
|
|
||||||
|
# Check if git is installed
|
||||||
|
gitSubprocess = subprocess.run(["git", "-v"], capture_output=True, text=True)
|
||||||
|
if gitSubprocess.returncode == 0:
|
||||||
|
prerequisites["git"] = True
|
||||||
|
|
||||||
|
# Check if hsd is installed
|
||||||
|
if os.path.exists("./hsd/bin/hsd"):
|
||||||
|
prerequisites["hsd"] = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return prerequisites
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def hsdInit():
|
||||||
|
if not HSD_INTERNAL_NODE:
|
||||||
|
return
|
||||||
|
prerequisites = checkPreRequisites()
|
||||||
|
|
||||||
|
PREREQ_MESSAGES = {
|
||||||
|
"node": "Install Node.js from https://nodejs.org/en/download (Version >= {minNodeVersion})",
|
||||||
|
"npm": "Install npm (version >= {minNPMVersion}) - usually comes with Node.js",
|
||||||
|
"git": "Install Git from https://git-scm.com/downloads"}
|
||||||
|
|
||||||
|
|
||||||
|
# Check if all prerequisites are met (except hsd)
|
||||||
|
if not all(prerequisites[key] for key in prerequisites if key != "hsd"):
|
||||||
|
print("HSD Internal Node prerequisites not met:")
|
||||||
|
for key, value in prerequisites.items():
|
||||||
|
if not value:
|
||||||
|
print(f" - {key} is missing or does not meet the version requirement.")
|
||||||
|
exit(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if hsd is installed
|
||||||
|
if not prerequisites["hsd"]:
|
||||||
|
print("HSD not found, installing...")
|
||||||
|
# If hsd folder exists, remove it
|
||||||
|
if os.path.exists("hsd"):
|
||||||
|
os.rmdir("hsd")
|
||||||
|
|
||||||
|
# Clone hsd repo
|
||||||
|
gitClone = subprocess.run(["git", "clone", "--depth", "1", "--branch", HSD_CONFIG.get("version", "latest"), "https://github.com/handshake-org/hsd.git", "hsd"], capture_output=True, text=True)
|
||||||
|
if gitClone.returncode != 0:
|
||||||
|
print("Failed to clone hsd repository:")
|
||||||
|
print(gitClone.stderr)
|
||||||
|
exit(1)
|
||||||
|
print("Cloned hsd repository.")
|
||||||
|
# Install hsd dependencies
|
||||||
|
print("Installing hsd dependencies...")
|
||||||
|
npmInstall = subprocess.run(["npm", "install"], cwd="hsd", capture_output=True, text=True)
|
||||||
|
if npmInstall.returncode != 0:
|
||||||
|
print("Failed to install hsd dependencies:")
|
||||||
|
print(npmInstall.stderr)
|
||||||
|
exit(1)
|
||||||
|
print("Installed hsd dependencies.")
|
||||||
|
|
||||||
|
def hsdStart():
|
||||||
|
global HSD_PROCESS
|
||||||
|
if not HSD_INTERNAL_NODE:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if hsd was started in the last 30 seconds
|
||||||
|
if os.path.exists("hsd.lock"):
|
||||||
|
lock_time = os.path.getmtime("hsd.lock")
|
||||||
|
if time.time() - lock_time < 30:
|
||||||
|
print("HSD was started recently, skipping start.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
os.remove("hsd.lock")
|
||||||
|
|
||||||
|
print("Starting HSD...")
|
||||||
|
# Create a lock file
|
||||||
|
with open("hsd.lock", "w") as f:
|
||||||
|
f.write(str(time.time()))
|
||||||
|
|
||||||
|
# Config lookups with defaults
|
||||||
|
chain_migrate = HSD_CONFIG.get("chainMigrate", False)
|
||||||
|
wallet_migrate = HSD_CONFIG.get("walletMigrate", False)
|
||||||
|
spv = HSD_CONFIG.get("spv", False)
|
||||||
|
|
||||||
|
# Base command
|
||||||
|
cmd = [
|
||||||
|
"node",
|
||||||
|
"./hsd/bin/hsd",
|
||||||
|
f"--network={HSD_NETWORK}",
|
||||||
|
f"--prefix={os.path.join(os.getcwd(), 'hsd-data')}",
|
||||||
|
f"--api-key={HSD_API}",
|
||||||
|
"--agent=FireWallet",
|
||||||
|
"--http-host=127.0.0.1",
|
||||||
|
"--log-console=false"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Conditionally add migration flags
|
||||||
|
if chain_migrate:
|
||||||
|
cmd.append(f"--chain-migrate={chain_migrate}")
|
||||||
|
if wallet_migrate:
|
||||||
|
cmd.append(f"--wallet-migrate={wallet_migrate}")
|
||||||
|
if spv:
|
||||||
|
cmd.append("--spv")
|
||||||
|
|
||||||
|
|
||||||
|
# Launch process
|
||||||
|
HSD_PROCESS = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
cwd=os.getcwd(),
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"HSD started with PID {HSD_PROCESS.pid}")
|
||||||
|
|
||||||
|
atexit.register(hsdStop)
|
||||||
|
|
||||||
|
# Handle Ctrl+C
|
||||||
|
try:
|
||||||
|
signal.signal(signal.SIGINT, lambda s, f: (hsdStop(), sys.exit(0)))
|
||||||
|
signal.signal(signal.SIGTERM, lambda s, f: (hsdStop(), sys.exit(0)))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def hsdStop():
|
||||||
|
global HSD_PROCESS
|
||||||
|
|
||||||
|
if HSD_PROCESS is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Stopping HSD...")
|
||||||
|
|
||||||
|
# Send SIGINT (like Ctrl+C)
|
||||||
|
HSD_PROCESS.send_signal(signal.SIGINT)
|
||||||
|
|
||||||
|
try:
|
||||||
|
HSD_PROCESS.wait(timeout=10) # wait for graceful exit
|
||||||
|
print("HSD shut down cleanly.")
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("HSD did not exit yet, is it alright???")
|
||||||
|
|
||||||
|
# Clean up lock file
|
||||||
|
if os.path.exists("hsd.lock"):
|
||||||
|
os.remove("hsd.lock")
|
||||||
|
|
||||||
|
HSD_PROCESS = None
|
||||||
|
|
||||||
|
def hsdRestart():
|
||||||
|
hsdStop()
|
||||||
|
time.sleep(2)
|
||||||
|
hsdStart()
|
||||||
|
|
||||||
|
|
||||||
|
checkPreRequisites()
|
||||||
|
hsdInit()
|
||||||
|
hsdStart()
|
||||||
|
# endregion
|
||||||
@@ -6,10 +6,14 @@ import subprocess
|
|||||||
import binascii
|
import binascii
|
||||||
import datetime
|
import datetime
|
||||||
import dns.asyncresolver
|
import dns.asyncresolver
|
||||||
|
import dns.message
|
||||||
|
import dns.query
|
||||||
|
import dns.rdatatype
|
||||||
import httpx
|
import httpx
|
||||||
from requests_doh import DNSOverHTTPSSession, add_dns_provider
|
from requests_doh import DNSOverHTTPSSession, add_dns_provider
|
||||||
import requests
|
import requests
|
||||||
import urllib3
|
import urllib3
|
||||||
|
from cryptography.x509.oid import ExtensionOID
|
||||||
|
|
||||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Disable insecure request warnings (since we are manually verifying the certificate)
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Disable insecure request warnings (since we are manually verifying the certificate)
|
||||||
|
|
||||||
@@ -56,7 +60,7 @@ def hip2(domain: str):
|
|||||||
|
|
||||||
domains = []
|
domains = []
|
||||||
for ext in cert_obj.extensions:
|
for ext in cert_obj.extensions:
|
||||||
if ext.oid == x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
|
if ext.oid == ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
|
||||||
san_list = ext.value.get_values_for_type(x509.DNSName)
|
san_list = ext.value.get_values_for_type(x509.DNSName)
|
||||||
domains.extend(san_list)
|
domains.extend(san_list)
|
||||||
|
|
||||||
@@ -120,13 +124,39 @@ def hip2(domain: str):
|
|||||||
print(f"Hip2: Lookup failed with error: {e}",flush=True)
|
print(f"Hip2: Lookup failed with error: {e}",flush=True)
|
||||||
return "Hip2: Lookup failed."
|
return "Hip2: Lookup failed."
|
||||||
|
|
||||||
|
def wallet_txt(domain: str, doh_url="https://hnsdoh.com/dns-query"):
|
||||||
|
with httpx.Client() as client:
|
||||||
|
q = dns.message.make_query(domain, dns.rdatatype.from_text("TYPE262"))
|
||||||
|
r = dns.query.https(q, doh_url, session=client)
|
||||||
|
|
||||||
|
if not r.answer:
|
||||||
|
return "No wallet address found for this domain"
|
||||||
|
|
||||||
|
wallet_record = "No WALLET record found"
|
||||||
|
for ans in r.answer:
|
||||||
|
raw = ans[0].to_wire() # type: ignore
|
||||||
|
try:
|
||||||
|
data = raw[1:].decode("utf-8", errors="ignore")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return f"Unknown WALLET record format: {raw.hex()}"
|
||||||
|
|
||||||
|
if data.startswith("HNS:"):
|
||||||
|
wallet_record = data[4:]
|
||||||
|
break
|
||||||
|
elif data.startswith("HNS "):
|
||||||
|
wallet_record = data[4:]
|
||||||
|
break
|
||||||
|
elif data.startswith('"HNS" '):
|
||||||
|
wallet_record = data[6:].strip('"')
|
||||||
|
break
|
||||||
|
return wallet_record
|
||||||
|
|
||||||
def resolve_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"):
|
def resolve_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"):
|
||||||
with httpx.Client() as client:
|
with httpx.Client() as client:
|
||||||
q = dns.message.make_query(query_name, dns.rdatatype.A)
|
q = dns.message.make_query(query_name, dns.rdatatype.A)
|
||||||
r = dns.query.https(q, doh_url, session=client)
|
r = dns.query.https(q, doh_url, session=client)
|
||||||
|
|
||||||
ip = r.answer[0][0].address
|
ip = r.answer[0][0].address # type: ignore
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
def resolve_TLSA_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"):
|
def resolve_TLSA_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"):
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ HSD_API=123480615465636893475aCwyaae6s45
|
|||||||
HSD_IP=localhost
|
HSD_IP=localhost
|
||||||
THEME=black
|
THEME=black
|
||||||
SHOW_EXPIRED=false
|
SHOW_EXPIRED=false
|
||||||
EXPLORER_TX=https://shakeshift.com/transaction/
|
EXPLORER_TX=https://shakeshift.com/transaction/
|
||||||
|
DISABLE_WALLETDNS=false
|
||||||
|
INTERNAL_HSD=false
|
||||||
8
hsdconfig.json
Normal file
8
hsdconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"version": "v8.0.0",
|
||||||
|
"chainMigrate":4,
|
||||||
|
"walletMigrate":7,
|
||||||
|
"minNodeVersion":20,
|
||||||
|
"minNpmVersion":8,
|
||||||
|
"spv": true
|
||||||
|
}
|
||||||
210
main.py
210
main.py
@@ -56,17 +56,12 @@ def blocks_to_time(blocks: int) -> str:
|
|||||||
if hours == 0:
|
if hours == 0:
|
||||||
return f"{days} days"
|
return f"{days} days"
|
||||||
return f"{days} days {hours} hrs"
|
return f"{days} days {hours} hrs"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
# Check if the user is logged in
|
# Check if the user is logged in
|
||||||
if request.cookies.get("account") is None:
|
if request.cookies.get("account") is None:
|
||||||
return redirect("/login")
|
return redirect("/login")
|
||||||
|
|
||||||
account = account_module.check_account(request.cookies.get("account"))
|
account = account_module.check_account(request.cookies.get("account"))
|
||||||
if not account:
|
if not account:
|
||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
@@ -83,6 +78,8 @@ def index():
|
|||||||
return render_template("index.html", account=account, plugins=plugins)
|
return render_template("index.html", account=account, plugins=plugins)
|
||||||
|
|
||||||
info = gitinfo.get_git_info()
|
info = gitinfo.get_git_info()
|
||||||
|
if info is None:
|
||||||
|
return render_template("index.html", account=account, plugins=plugins)
|
||||||
branch = info['refs']
|
branch = info['refs']
|
||||||
commit = info['commit']
|
commit = info['commit']
|
||||||
if commit != latestVersion(branch):
|
if commit != latestVersion(branch):
|
||||||
@@ -114,7 +111,7 @@ def transactions():
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
# Get the page parameter
|
# Get the page parameter
|
||||||
page = request.args.get('page')
|
page = request.args.get('page', 1)
|
||||||
try:
|
try:
|
||||||
page = int(page)
|
page = int(page)
|
||||||
except:
|
except:
|
||||||
@@ -135,6 +132,8 @@ def send_page():
|
|||||||
return redirect("/login")
|
return redirect("/login")
|
||||||
|
|
||||||
account = account_module.check_account(request.cookies.get("account"))
|
account = account_module.check_account(request.cookies.get("account"))
|
||||||
|
if not account:
|
||||||
|
return redirect("/logout")
|
||||||
max = account_module.getBalance(account)['available']
|
max = account_module.getBalance(account)['available']
|
||||||
# Subtract approx fee
|
# Subtract approx fee
|
||||||
max = max - fees
|
max = max - fees
|
||||||
@@ -170,28 +169,28 @@ def send():
|
|||||||
amount = request.form.get("amount")
|
amount = request.form.get("amount")
|
||||||
|
|
||||||
if address is None or amount is None:
|
if address is None or amount is None:
|
||||||
return redirect("/send?message=Invalid address or amount&address=" + address + "&amount=" + amount)
|
return redirect(f"/send?message=Invalid address or amount&address={address}&amount={amount}")
|
||||||
|
|
||||||
address_check = account_module.check_address(address.strip(),True,True)
|
address_check = account_module.check_address(address.strip(),True,True)
|
||||||
if not address_check:
|
if not address_check:
|
||||||
return redirect("/send?message=Invalid address&address=" + address + "&amount=" + amount)
|
return redirect(f"/send?message=Invalid address&address={address}&amount={amount}")
|
||||||
|
|
||||||
address = address_check
|
address = address_check
|
||||||
# Check if the amount is valid
|
# Check if the amount is valid
|
||||||
if re.match(r"^\d+(\.\d+)?$", amount) is None:
|
if re.match(r"^\d+(\.\d+)?$", amount) is None:
|
||||||
return redirect("/send?message=Invalid amount&address=" + address + "&amount=" + amount)
|
return redirect(f"/send?message=Invalid amount&address={address}&amount={amount}")
|
||||||
|
|
||||||
# Check if the amount is valid
|
# Check if the amount is valid
|
||||||
amount = float(amount)
|
amount = float(amount)
|
||||||
if amount <= 0:
|
if amount <= 0:
|
||||||
return redirect("/send?message=Invalid amount&address=" + address + "&amount=" + str(amount))
|
return redirect(f"/send?message=Invalid amount&address={address}&amount={amount}")
|
||||||
|
|
||||||
if amount > account_module.getBalance(account)['available'] - fees:
|
if amount > account_module.getBalance(account)['available'] - fees:
|
||||||
return redirect("/send?message=Not enough funds to transfer&address=" + address + "&amount=" + str(amount))
|
return redirect(f"/send?message=Not enough funds to transfer&address={address}&amount={amount}")
|
||||||
|
|
||||||
toAddress = address
|
toAddress = address
|
||||||
if request.form.get('address') != address:
|
if request.form.get('address') != address:
|
||||||
toAddress = request.form.get('address') + "<br>" + address
|
toAddress = f"{request.form.get('address')}<br>{address}"
|
||||||
|
|
||||||
action = f"Send HNS to {request.form.get('address')}"
|
action = f"Send HNS to {request.form.get('address')}"
|
||||||
content = f"Are you sure you want to send {amount} HNS to {toAddress}<br><br>"
|
content = f"Are you sure you want to send {amount} HNS to {toAddress}<br><br>"
|
||||||
@@ -202,7 +201,6 @@ def send():
|
|||||||
|
|
||||||
|
|
||||||
return render_template("confirm.html", account=account_module.check_account(request.cookies.get("account")),
|
return render_template("confirm.html", account=account_module.check_account(request.cookies.get("account")),
|
||||||
|
|
||||||
action=action,
|
action=action,
|
||||||
content=content,cancel=cancel,confirm=confirm)
|
content=content,cancel=cancel,confirm=confirm)
|
||||||
|
|
||||||
@@ -211,20 +209,20 @@ def send():
|
|||||||
def sendConfirmed():
|
def sendConfirmed():
|
||||||
|
|
||||||
address = request.args.get("address")
|
address = request.args.get("address")
|
||||||
amount = float(request.args.get("amount"))
|
amount = float(request.args.get("amount","0"))
|
||||||
response = account_module.send(request.cookies.get("account"),address,amount)
|
response = account_module.send(request.cookies.get("account"),address,amount)
|
||||||
if 'error' in response and response['error'] != None:
|
if 'error' in response and response['error'] != None:
|
||||||
# If error is a dict get the message
|
# If error is a dict get the message
|
||||||
if isinstance(response['error'], dict):
|
if isinstance(response['error'], dict):
|
||||||
if 'message' in response['error']:
|
if 'message' in response['error']:
|
||||||
return redirect("/send?message=" + response['error']['message'] + "&address=" + address + "&amount=" + str(amount))
|
return redirect(f"/send?message={response['error']['message']}&address={address}&amount={amount}")
|
||||||
else:
|
else:
|
||||||
return redirect("/send?message=" + str(response['error']) + "&address=" + address + "&amount=" + str(amount))
|
return redirect(f"/send?message={response['error']}&address={address}&amount={amount}")
|
||||||
|
|
||||||
# If error is a string
|
# If error is a string
|
||||||
return redirect("/send?message=" + response['error'] + "&address=" + address + "&amount=" + str(amount))
|
return redirect(f"/send?message={response['error']}&address={address}&amount={amount}")
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['tx'])
|
return redirect(f"/success?tx={response['tx']}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -363,6 +361,9 @@ def revealAllBids():
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
response = account_module.revealAll(request.cookies.get("account"))
|
response = account_module.revealAll(request.cookies.get("account"))
|
||||||
|
if not response:
|
||||||
|
return redirect("/auctions?message=Failed to reveal bids")
|
||||||
|
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
if response['error'] != None:
|
if response['error'] != None:
|
||||||
if response['error']['message'] == "Nothing to do.":
|
if response['error']['message'] == "Nothing to do.":
|
||||||
@@ -383,6 +384,9 @@ def redeemAllBids():
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
response = account_module.redeemAll(request.cookies.get("account"))
|
response = account_module.redeemAll(request.cookies.get("account"))
|
||||||
|
if not response:
|
||||||
|
return redirect("/auctions?message=Failed to redeem bids")
|
||||||
|
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
if response['error'] != None:
|
if response['error'] != None:
|
||||||
if response['error']['message'] == "Nothing to do.":
|
if response['error']['message'] == "Nothing to do.":
|
||||||
@@ -402,13 +406,16 @@ def registerAllDomains():
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
response = account_module.registerAll(request.cookies.get("account"))
|
response = account_module.registerAll(request.cookies.get("account"))
|
||||||
|
if not response:
|
||||||
|
return redirect("/auctions?message=Failed to register domains")
|
||||||
|
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
if response['error'] != None:
|
if response['error'] != None:
|
||||||
if response['error']['message'] == "Nothing to do.":
|
if response['error']['message'] == "Nothing to do.":
|
||||||
return redirect("/auctions?message=No domains to register")
|
return redirect("/auctions?message=No domains to register")
|
||||||
return redirect("/auctions?message=" + response['error']['message'])
|
return redirect("/auctions?message=" + response['error']['message'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/all/finalize')
|
@app.route('/all/finalize')
|
||||||
def finalizeAllBids():
|
def finalizeAllBids():
|
||||||
@@ -427,7 +434,7 @@ def finalizeAllBids():
|
|||||||
return redirect("/dashboard?message=No domains to finalize")
|
return redirect("/dashboard?message=No domains to finalize")
|
||||||
return redirect("/dashboard?message=" + response['error']['message'])
|
return redirect("/dashboard?message=" + response['error']['message'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@app.route('/search')
|
@app.route('/search')
|
||||||
@@ -441,6 +448,8 @@ def search():
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
search_term = request.args.get("q")
|
search_term = request.args.get("q")
|
||||||
|
if search_term is None:
|
||||||
|
return redirect("/")
|
||||||
search_term = search_term.lower().strip()
|
search_term = search_term.lower().strip()
|
||||||
|
|
||||||
# Replace spaces with hyphens
|
# Replace spaces with hyphens
|
||||||
@@ -457,7 +466,7 @@ def search():
|
|||||||
# Execute domain plugins
|
# Execute domain plugins
|
||||||
searchFunctions = plugins_module.getSearchFunctions()
|
searchFunctions = plugins_module.getSearchFunctions()
|
||||||
for function in searchFunctions:
|
for function in searchFunctions:
|
||||||
functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":search_term},account_module.check_account(request.cookies.get("account")))
|
functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":search_term},account)
|
||||||
plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"]))
|
plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"]))
|
||||||
|
|
||||||
plugins += "</div>"
|
plugins += "</div>"
|
||||||
@@ -475,6 +484,7 @@ def search():
|
|||||||
|
|
||||||
state = domain['info']['state']
|
state = domain['info']['state']
|
||||||
stats = domain['info']['stats']
|
stats = domain['info']['stats']
|
||||||
|
next = ""
|
||||||
if state == 'CLOSED':
|
if state == 'CLOSED':
|
||||||
if domain['info']['registered']:
|
if domain['info']['registered']:
|
||||||
state = 'REGISTERED'
|
state = 'REGISTERED'
|
||||||
@@ -571,7 +581,7 @@ def manage(domain: str):
|
|||||||
# Execute domain plugins
|
# Execute domain plugins
|
||||||
domainFunctions = plugins_module.getDomainFunctions()
|
domainFunctions = plugins_module.getDomainFunctions()
|
||||||
for function in domainFunctions:
|
for function in domainFunctions:
|
||||||
functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":domain},account_module.check_account(request.cookies.get("account")))
|
functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":domain},account)
|
||||||
plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"]))
|
plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"]))
|
||||||
|
|
||||||
plugins += "</div>"
|
plugins += "</div>"
|
||||||
@@ -676,7 +686,7 @@ def revokeConfirm(domain: str):
|
|||||||
print(response)
|
print(response)
|
||||||
return redirect("/manage/" + domain + "?error=" + response['error']['message'])
|
return redirect("/manage/" + domain + "?error=" + response['error']['message'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/manage/<domain>/renew')
|
@app.route('/manage/<domain>/renew')
|
||||||
def renew(domain: str):
|
def renew(domain: str):
|
||||||
@@ -690,7 +700,7 @@ def renew(domain: str):
|
|||||||
|
|
||||||
domain = domain.lower()
|
domain = domain.lower()
|
||||||
response = account_module.renewDomain(request.cookies.get("account"),domain)
|
response = account_module.renewDomain(request.cookies.get("account"),domain)
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/manage/<domain>/edit')
|
@app.route('/manage/<domain>/edit')
|
||||||
def editPage(domain: str):
|
def editPage(domain: str):
|
||||||
@@ -716,8 +726,11 @@ def editPage(domain: str):
|
|||||||
dns = urllib.parse.unquote(user_edits)
|
dns = urllib.parse.unquote(user_edits)
|
||||||
else:
|
else:
|
||||||
dns = account_module.getDNS(domain)
|
dns = account_module.getDNS(domain)
|
||||||
|
|
||||||
dns = json.loads(dns)
|
if dns and isinstance(dns, str):
|
||||||
|
dns = json.loads(dns)
|
||||||
|
else:
|
||||||
|
dns = []
|
||||||
|
|
||||||
# Check if new records have been added
|
# Check if new records have been added
|
||||||
dnsType = request.args.get("type")
|
dnsType = request.args.get("type")
|
||||||
@@ -733,14 +746,14 @@ def editPage(domain: str):
|
|||||||
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(str(raw_dns)) + "&error=Invalid DS record")
|
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(str(raw_dns)) + "&error=Invalid DS record")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ds[0] = int(ds[0])
|
key_tag = int(ds[0])
|
||||||
ds[1] = int(ds[1])
|
algorithm = int(ds[1])
|
||||||
ds[2] = int(ds[2])
|
digest_type = int(ds[2])
|
||||||
except:
|
except:
|
||||||
raw_dns = str(dns).replace("'",'"')
|
raw_dns = str(dns).replace("'",'"')
|
||||||
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(str(raw_dns)) + "&error=Invalid DS record")
|
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(str(raw_dns)) + "&error=Invalid DS record")
|
||||||
finally:
|
|
||||||
dns.append({"type": dnsType, "keyTag": ds[0], "algorithm": ds[1], "digestType": ds[2], "digest": ds[3]})
|
dns.append({"type": dnsType, "keyTag": key_tag, "algorithm": algorithm, "digestType": digest_type, "digest": ds[3]})
|
||||||
|
|
||||||
dns = json.dumps(dns).replace("'",'"')
|
dns = json.dumps(dns).replace("'",'"')
|
||||||
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(dns))
|
return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(dns))
|
||||||
@@ -770,13 +783,15 @@ def editSave(domain: str):
|
|||||||
|
|
||||||
domain = domain.lower()
|
domain = domain.lower()
|
||||||
dns = request.args.get("dns")
|
dns = request.args.get("dns")
|
||||||
|
if dns is None:
|
||||||
|
return redirect(f"/manage/{domain}/edit?error=No DNS records provided")
|
||||||
raw_dns = dns
|
raw_dns = dns
|
||||||
dns = urllib.parse.unquote(dns)
|
dns = urllib.parse.unquote(dns)
|
||||||
response = account_module.setDNS(request.cookies.get("account"),domain,dns)
|
response = account_module.setDNS(request.cookies.get("account"),domain,dns)
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
print(response)
|
print(response)
|
||||||
return redirect("/manage/" + domain + "/edit?dns="+raw_dns+"&error=" + str(response['error']))
|
return redirect(f"/manage/{domain}/edit?dns={raw_dns}&error={response['error']}")
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/manage/<domain>/transfer')
|
@app.route('/manage/<domain>/transfer')
|
||||||
def transfer(domain):
|
def transfer(domain):
|
||||||
@@ -801,7 +816,7 @@ def transfer(domain):
|
|||||||
|
|
||||||
toAddress = address
|
toAddress = address
|
||||||
if request.form.get('address') != address:
|
if request.form.get('address') != address:
|
||||||
toAddress = request.args.get('address') + "<br>" + address
|
toAddress = f"{request.args.get('address')}<br>{address}"
|
||||||
|
|
||||||
action = f"Send {domain}/ to {request.form.get('address')}"
|
action = f"Send {domain}/ to {request.form.get('address')}"
|
||||||
content = f"Are you sure you want to send {domain}/ to {toAddress}<br><br>"
|
content = f"Are you sure you want to send {domain}/ to {toAddress}<br><br>"
|
||||||
@@ -811,9 +826,7 @@ def transfer(domain):
|
|||||||
confirm = f"/manage/{domain}/transfer/confirm?address={address}"
|
confirm = f"/manage/{domain}/transfer/confirm?address={address}"
|
||||||
|
|
||||||
|
|
||||||
return render_template("confirm.html", account=account_module.check_account(request.cookies.get("account")),
|
return render_template("confirm.html", account=account,action=action,
|
||||||
|
|
||||||
action=action,
|
|
||||||
content=content,cancel=cancel,confirm=confirm)
|
content=content,cancel=cancel,confirm=confirm)
|
||||||
|
|
||||||
@app.route('/manage/<domain>/sign')
|
@app.route('/manage/<domain>/sign')
|
||||||
@@ -836,7 +849,7 @@ def signMessage(domain):
|
|||||||
signedMessage = account_module.signMessage(request.cookies.get("account"),domain,message)
|
signedMessage = account_module.signMessage(request.cookies.get("account"),domain,message)
|
||||||
if signedMessage["error"] != None:
|
if signedMessage["error"] != None:
|
||||||
return redirect("/manage/" + domain + "?error=" + signedMessage["error"])
|
return redirect("/manage/" + domain + "?error=" + signedMessage["error"])
|
||||||
content += "Signature:<br><code>" + signedMessage["result"] + "</code><br><br>"
|
content += f"Signature:<br><code>{signedMessage["result"]}</code><br><br>"
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
@@ -853,8 +866,7 @@ def signMessage(domain):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render_template("message.html", account=account,
|
return render_template("message.html", account=account,
|
||||||
|
|
||||||
title="Sign Message",content=content)
|
title="Sign Message",content=content)
|
||||||
|
|
||||||
|
|
||||||
@@ -873,7 +885,7 @@ def transferConfirm(domain):
|
|||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
return redirect("/manage/" + domain + "?error=" + response['error'])
|
return redirect("/manage/" + domain + "?error=" + response['error'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
|
|
||||||
@app.route('/auction/<domain>')
|
@app.route('/auction/<domain>')
|
||||||
@@ -917,20 +929,9 @@ def auction(domain):
|
|||||||
|
|
||||||
state = domainInfo['info']['state']
|
state = domainInfo['info']['state']
|
||||||
next_action = ''
|
next_action = ''
|
||||||
|
next = ""
|
||||||
|
|
||||||
# bids = account_module.getBids(account,search_term)
|
|
||||||
bids = []
|
bids = []
|
||||||
# if bids == []:
|
|
||||||
# bids = "No bids found"
|
|
||||||
# next_action = f'<a href="/auction/{domain}/scan">Rescan Auction</a>'
|
|
||||||
# else:
|
|
||||||
# reveals = account_module.getReveals(account,search_term)
|
|
||||||
# for reveal in reveals:
|
|
||||||
# # Get TX
|
|
||||||
# revealInfo = account_module.getRevealTX(reveal)
|
|
||||||
# reveal['bid'] = revealInfo
|
|
||||||
# bids = render.bids(bids,reveals)
|
|
||||||
|
|
||||||
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
||||||
if state == 'CLOSED':
|
if state == 'CLOSED':
|
||||||
if not domainInfo['info']['registered']:
|
if not domainInfo['info']['registered']:
|
||||||
@@ -1010,8 +1011,8 @@ def bid(domain):
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
domain = domain.lower()
|
domain = domain.lower()
|
||||||
bid = request.args.get("bid")
|
bid = request.args.get("bid","")
|
||||||
blind = request.args.get("blind")
|
blind = request.args.get("blind","")
|
||||||
|
|
||||||
if bid == "":
|
if bid == "":
|
||||||
bid = 0
|
bid = 0
|
||||||
@@ -1056,8 +1057,8 @@ def bid_confirm(domain):
|
|||||||
return redirect("/logout")
|
return redirect("/logout")
|
||||||
|
|
||||||
domain = domain.lower()
|
domain = domain.lower()
|
||||||
bid = request.args.get("bid")
|
bid = request.args.get("bid","")
|
||||||
blind = request.args.get("blind")
|
blind = request.args.get("blind","")
|
||||||
|
|
||||||
if bid == "":
|
if bid == "":
|
||||||
bid = 0
|
bid = 0
|
||||||
@@ -1076,7 +1077,7 @@ def bid_confirm(domain):
|
|||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
return redirect("/auction/" + domain + "?error=" + response['error']['message'])
|
return redirect("/auction/" + domain + "?error=" + response['error']['message'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/auction/<domain>/open')
|
@app.route('/auction/<domain>/open')
|
||||||
def open_auction(domain):
|
def open_auction(domain):
|
||||||
@@ -1095,7 +1096,7 @@ def open_auction(domain):
|
|||||||
if response['error'] != None:
|
if response['error'] != None:
|
||||||
return redirect("/auction/" + domain + "?error=" + response['error']['message'])
|
return redirect("/auction/" + domain + "?error=" + response['error']['message'])
|
||||||
|
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/auction/<domain>/reveal')
|
@app.route('/auction/<domain>/reveal')
|
||||||
def reveal_auction(domain):
|
def reveal_auction(domain):
|
||||||
@@ -1110,8 +1111,8 @@ def reveal_auction(domain):
|
|||||||
domain = domain.lower()
|
domain = domain.lower()
|
||||||
response = account_module.revealAuction(request.cookies.get("account"),domain)
|
response = account_module.revealAuction(request.cookies.get("account"),domain)
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
return redirect("/auction/" + domain + "?message=" + response['error']['message'])
|
return redirect(f"/auction/{domain}?message={response['error']}")
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
@app.route('/auction/<domain>/register')
|
@app.route('/auction/<domain>/register')
|
||||||
def registerdomain(domain):
|
def registerdomain(domain):
|
||||||
@@ -1126,7 +1127,7 @@ def registerdomain(domain):
|
|||||||
response = account_module.register(request.cookies.get("account"),domain)
|
response = account_module.register(request.cookies.get("account"),domain)
|
||||||
if 'error' in response:
|
if 'error' in response:
|
||||||
return redirect("/auction/" + domain + "?message=" + response['error']['message'])
|
return redirect("/auction/" + domain + "?message=" + response['error']['message'])
|
||||||
return redirect("/success?tx=" + response['hash'])
|
return redirect(f"/success?tx={response['hash']}")
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Settings
|
#region Settings
|
||||||
@@ -1149,10 +1150,14 @@ def settings():
|
|||||||
|
|
||||||
if not os.path.exists(".git"):
|
if not os.path.exists(".git"):
|
||||||
return render_template("settings.html", account=account,
|
return render_template("settings.html", account=account,
|
||||||
|
|
||||||
hsd_version=account_module.hsdVersion(False),
|
hsd_version=account_module.hsdVersion(False),
|
||||||
error=error,success=success,version="Error")
|
error=error,success=success,version="Error",internal=account_module.HSD_INTERNAL_NODE)
|
||||||
info = gitinfo.get_git_info()
|
info = gitinfo.get_git_info()
|
||||||
|
if not info:
|
||||||
|
return render_template("settings.html", account=account,
|
||||||
|
hsd_version=account_module.hsdVersion(False),
|
||||||
|
error=error,success=success,version="Error",internal=account_module.HSD_INTERNAL_NODE)
|
||||||
|
|
||||||
branch = info['refs']
|
branch = info['refs']
|
||||||
if branch != "main":
|
if branch != "main":
|
||||||
branch = f"({branch})"
|
branch = f"({branch})"
|
||||||
@@ -1166,7 +1171,7 @@ def settings():
|
|||||||
version += ' (New version available)'
|
version += ' (New version available)'
|
||||||
return render_template("settings.html", account=account,
|
return render_template("settings.html", account=account,
|
||||||
hsd_version=account_module.hsdVersion(False),
|
hsd_version=account_module.hsdVersion(False),
|
||||||
error=error,success=success,version=version)
|
error=error,success=success,version=version,internal=account_module.HSD_INTERNAL_NODE)
|
||||||
|
|
||||||
@app.route('/settings/<action>')
|
@app.route('/settings/<action>')
|
||||||
def settings_action(action):
|
def settings_action(action):
|
||||||
@@ -1183,29 +1188,36 @@ def settings_action(action):
|
|||||||
if 'error' in resp:
|
if 'error' in resp:
|
||||||
return redirect("/settings?error=" + str(resp['error']))
|
return redirect("/settings?error=" + str(resp['error']))
|
||||||
return redirect("/settings?success=Rescan started")
|
return redirect("/settings?success=Rescan started")
|
||||||
elif action == "resend":
|
|
||||||
|
if action == "resend":
|
||||||
resp = account_module.resendTXs()
|
resp = account_module.resendTXs()
|
||||||
if 'error' in resp:
|
if 'error' in resp:
|
||||||
return redirect("/settings?error=" + str(resp['error']))
|
return redirect("/settings?error=" + str(resp['error']))
|
||||||
return redirect("/settings?success=Resent transactions")
|
return redirect("/settings?success=Resent transactions")
|
||||||
|
|
||||||
|
|
||||||
elif action == "zap":
|
if action == "zap":
|
||||||
resp = account_module.zapTXs(request.cookies.get("account"))
|
resp = account_module.zapTXs(request.cookies.get("account"))
|
||||||
if 'error' in resp:
|
if type(resp) == dict and 'error' in resp:
|
||||||
return redirect("/settings?error=" + str(resp['error']))
|
return redirect("/settings?error=" + str(resp['error']))
|
||||||
return redirect("/settings?success=Zapped transactions")
|
return redirect("/settings?success=Zapped transactions")
|
||||||
elif action == "xpub":
|
|
||||||
|
if action == "xpub":
|
||||||
xpub = account_module.getxPub(request.cookies.get("account"))
|
xpub = account_module.getxPub(request.cookies.get("account"))
|
||||||
content = "<br><br>"
|
content = "<br><br>"
|
||||||
content += "<textarea style='display: none;' id='data' rows='4' cols='50'>"+xpub+"</textarea>"
|
content += f"<textarea style='display: none;' id='data' rows='4' cols='50'>{xpub}</textarea>"
|
||||||
content += "<script>function copyToClipboard() {var copyText = document.getElementById('data');copyText.style.display = 'block';copyText.select();copyText.setSelectionRange(0, 99999);document.execCommand('copy');copyText.style.display = 'none';var copyButton = document.getElementById('copyButton');copyButton.innerHTML='Copied';}</script>"
|
content += "<script>function copyToClipboard() {var copyText = document.getElementById('data');copyText.style.display = 'block';copyText.select();copyText.setSelectionRange(0, 99999);document.execCommand('copy');copyText.style.display = 'none';var copyButton = document.getElementById('copyButton');copyButton.innerHTML='Copied';}</script>"
|
||||||
content += "<button id='copyButton' onclick='copyToClipboard()' class='btn btn-secondary'>Copy to clipboard</button>"
|
content += "<button id='copyButton' onclick='copyToClipboard()' class='btn btn-secondary'>Copy to clipboard</button>"
|
||||||
|
|
||||||
return render_template("message.html", account=account,
|
return render_template("message.html", account=account,
|
||||||
|
|
||||||
title="xPub Key",
|
title="xPub Key",
|
||||||
content="<code>"+xpub+"</code>" + content)
|
content=f"<code>{xpub}</code>{content}")
|
||||||
|
|
||||||
|
if action == "restart":
|
||||||
|
resp = account_module.hsdRestart()
|
||||||
|
return render_template("message.html", account=account,
|
||||||
|
title="Restarting",
|
||||||
|
content="The node is restarting. This may take a minute or two. You can close this window.")
|
||||||
|
|
||||||
return redirect("/settings?error=Invalid action")
|
return redirect("/settings?error=Invalid action")
|
||||||
|
|
||||||
@@ -1215,6 +1227,9 @@ def upload_image():
|
|||||||
return redirect("/login?message=Not logged in")
|
return redirect("/login?message=Not logged in")
|
||||||
|
|
||||||
account = request.cookies.get("account")
|
account = request.cookies.get("account")
|
||||||
|
account = account_module.check_account(account)
|
||||||
|
if not account:
|
||||||
|
return redirect("/logout")
|
||||||
|
|
||||||
if not os.path.exists('user_data/images'):
|
if not os.path.exists('user_data/images'):
|
||||||
os.mkdir('user_data/images')
|
os.mkdir('user_data/images')
|
||||||
@@ -1224,11 +1239,12 @@ def upload_image():
|
|||||||
file = request.files['image']
|
file = request.files['image']
|
||||||
if file.filename == '':
|
if file.filename == '':
|
||||||
return redirect("/settings?error=No file selected")
|
return redirect("/settings?error=No file selected")
|
||||||
if file:
|
if file and file.filename:
|
||||||
filepath = os.path.join(f'user_data/images/{account.split(":")[0]}.{file.filename.split(".")[-1]}')
|
filepath = os.path.join(f'user_data/images/{account}.{file.filename.split(".")[-1]}')
|
||||||
file.save(filepath)
|
file.save(filepath)
|
||||||
return redirect("/settings?success=File uploaded successfully")
|
return redirect("/settings?success=File uploaded successfully")
|
||||||
|
|
||||||
|
return redirect("/settings?error=An error occurred")
|
||||||
|
|
||||||
def latestVersion(branch):
|
def latestVersion(branch):
|
||||||
result = requests.get(f"https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches")
|
result = requests.get(f"https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches")
|
||||||
@@ -1250,6 +1266,9 @@ def login():
|
|||||||
wallets = account_module.listWallets()
|
wallets = account_module.listWallets()
|
||||||
wallets = render.wallets(wallets)
|
wallets = render.wallets(wallets)
|
||||||
|
|
||||||
|
# If there are no wallets redirect to either register or import
|
||||||
|
if len(wallets) == 0:
|
||||||
|
return redirect("/welcome")
|
||||||
|
|
||||||
if 'message' in request.args:
|
if 'message' in request.args:
|
||||||
return render_template("login.html",
|
return render_template("login.html",
|
||||||
@@ -1265,6 +1284,12 @@ def login_post():
|
|||||||
account = request.form.get("account")
|
account = request.form.get("account")
|
||||||
password = request.form.get("password")
|
password = request.form.get("password")
|
||||||
|
|
||||||
|
if account == None or password == None:
|
||||||
|
wallets = account_module.listWallets()
|
||||||
|
wallets = render.wallets(wallets)
|
||||||
|
return render_template("login.html",
|
||||||
|
error="Invalid account or password",wallets=wallets)
|
||||||
|
|
||||||
# Check if the account is valid
|
# Check if the account is valid
|
||||||
if account.count(":") > 0:
|
if account.count(":") > 0:
|
||||||
wallets = account_module.listWallets()
|
wallets = account_module.listWallets()
|
||||||
@@ -1280,8 +1305,6 @@ def login_post():
|
|||||||
wallets = render.wallets(wallets)
|
wallets = render.wallets(wallets)
|
||||||
return render_template("login.html",
|
return render_template("login.html",
|
||||||
error="Invalid account or password",wallets=wallets)
|
error="Invalid account or password",wallets=wallets)
|
||||||
|
|
||||||
|
|
||||||
# Set the cookie
|
# Set the cookie
|
||||||
response = make_response(redirect("/"))
|
response = make_response(redirect("/"))
|
||||||
response.set_cookie("account", account)
|
response.set_cookie("account", account)
|
||||||
@@ -1300,6 +1323,11 @@ def register():
|
|||||||
password = request.form.get("password")
|
password = request.form.get("password")
|
||||||
repeatPassword = request.form.get("password_repeat")
|
repeatPassword = request.form.get("password_repeat")
|
||||||
|
|
||||||
|
if account == None or password == None or repeatPassword == None:
|
||||||
|
return render_template("register.html",
|
||||||
|
error="Invalid account or password",
|
||||||
|
name=account,password=password,password_repeat=repeatPassword)
|
||||||
|
|
||||||
# Check if the passwords match
|
# Check if the passwords match
|
||||||
if password != repeatPassword:
|
if password != repeatPassword:
|
||||||
return render_template("register.html",
|
return render_template("register.html",
|
||||||
@@ -1329,10 +1357,8 @@ def register():
|
|||||||
|
|
||||||
|
|
||||||
# Set the cookie
|
# Set the cookie
|
||||||
response = make_response(render_template("message.html",
|
response = make_response(render_template("message.html",title="Account Created",
|
||||||
|
content=f"Your account has been created. Here is your seed phrase. Please write it down and keep it safe as it will not be shown again<br><br>{response['seed']}"))
|
||||||
title="Account Created",
|
|
||||||
content="Your account has been created. Here is your seed phrase. Please write it down and keep it safe as it will not be shown again<br><br>" + response['seed']))
|
|
||||||
response.set_cookie("account", account+":"+password)
|
response.set_cookie("account", account+":"+password)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -1344,6 +1370,12 @@ def import_wallet():
|
|||||||
repeatPassword = request.form.get("password_repeat")
|
repeatPassword = request.form.get("password_repeat")
|
||||||
seed = request.form.get("seed")
|
seed = request.form.get("seed")
|
||||||
|
|
||||||
|
if account == None or password == None or repeatPassword == None or seed == None:
|
||||||
|
return render_template("import-wallet.html",
|
||||||
|
error="Invalid account, password or seed",
|
||||||
|
name=account,password=password,password_repeat=repeatPassword,
|
||||||
|
seed=seed)
|
||||||
|
|
||||||
# Check if the passwords match
|
# Check if the passwords match
|
||||||
if password != repeatPassword:
|
if password != repeatPassword:
|
||||||
return render_template("import-wallet.html",
|
return render_template("import-wallet.html",
|
||||||
@@ -1560,6 +1592,7 @@ def api_hsd(function):
|
|||||||
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {}
|
||||||
state = domainInfo['info']['state']
|
state = domainInfo['info']['state']
|
||||||
next_action = ""
|
next_action = ""
|
||||||
|
next = ""
|
||||||
if state == 'CLOSED':
|
if state == 'CLOSED':
|
||||||
if not domainInfo['info']['registered']:
|
if not domainInfo['info']['registered']:
|
||||||
if account_module.isOwnDomain(account,domain):
|
if account_module.isOwnDomain(account,domain):
|
||||||
@@ -1638,7 +1671,10 @@ def api_wallet(function):
|
|||||||
return jsonify({"error": "Not logged in"})
|
return jsonify({"error": "Not logged in"})
|
||||||
|
|
||||||
account = account_module.check_account(request.cookies.get("account"))
|
account = account_module.check_account(request.cookies.get("account"))
|
||||||
password = request.cookies.get("account").split(":")[1]
|
if not account:
|
||||||
|
return jsonify({"error": "Invalid account"})
|
||||||
|
|
||||||
|
password = request.cookies.get("account","").split(":")[1]
|
||||||
if not account:
|
if not account:
|
||||||
return jsonify({"error": "Invalid account"})
|
return jsonify({"error": "Invalid account"})
|
||||||
|
|
||||||
@@ -1672,7 +1708,7 @@ def api_wallet(function):
|
|||||||
|
|
||||||
if function == "domains":
|
if function == "domains":
|
||||||
domains = account_module.getDomains(account)
|
domains = account_module.getDomains(account)
|
||||||
if 'error' in domains:
|
if type(domains) == dict and 'error' in domains:
|
||||||
return jsonify({"result": [], "error": domains['error']})
|
return jsonify({"result": [], "error": domains['error']})
|
||||||
|
|
||||||
# Add nameRender to each domain
|
# Add nameRender to each domain
|
||||||
@@ -1683,7 +1719,7 @@ def api_wallet(function):
|
|||||||
|
|
||||||
if function == "transactions":
|
if function == "transactions":
|
||||||
# Get the page parameter
|
# Get the page parameter
|
||||||
page = request.args.get('page')
|
page = request.args.get('page', 1)
|
||||||
try:
|
try:
|
||||||
page = int(page)
|
page = int(page)
|
||||||
except:
|
except:
|
||||||
@@ -1759,7 +1795,7 @@ def api_wallet_mobile(function):
|
|||||||
return jsonify({"error": "Not logged in"})
|
return jsonify({"error": "Not logged in"})
|
||||||
|
|
||||||
account = account_module.check_account(request.cookies.get("account"))
|
account = account_module.check_account(request.cookies.get("account"))
|
||||||
password = request.cookies.get("account").split(":")[1]
|
password = request.cookies.get("account","").split(":")[1]
|
||||||
if not account:
|
if not account:
|
||||||
return jsonify({"error": "Invalid account"})
|
return jsonify({"error": "Invalid account"})
|
||||||
|
|
||||||
@@ -1821,7 +1857,11 @@ def renderDomain(name: str) -> str:
|
|||||||
#region Assets and default pages
|
#region Assets and default pages
|
||||||
@app.route('/qr/<data>')
|
@app.route('/qr/<data>')
|
||||||
def qr(data):
|
def qr(data):
|
||||||
return send_file(qrcode(data, mode="raw"), mimetype="image/png")
|
|
||||||
|
output = qrcode(data, mode="raw")
|
||||||
|
if output is None:
|
||||||
|
return jsonify({"error": "Invalid data"}), 400
|
||||||
|
return send_file(output, mimetype="image/png")
|
||||||
|
|
||||||
# Theme
|
# Theme
|
||||||
@app.route('/assets/css/styles.min.css')
|
@app.route('/assets/css/styles.min.css')
|
||||||
|
|||||||
17
plugin.py
17
plugin.py
@@ -148,11 +148,14 @@ def getPluginData(pluginStr: str):
|
|||||||
|
|
||||||
|
|
||||||
def getPluginFunctions(plugin: str):
|
def getPluginFunctions(plugin: str):
|
||||||
plugin = import_module(plugin.replace("/","."))
|
imported_plugin = import_module(plugin.replace("/","."))
|
||||||
return plugin.functions
|
return imported_plugin.functions
|
||||||
|
|
||||||
|
|
||||||
def runPluginFunction(plugin: str, function: str, params: dict, authentication: str):
|
def runPluginFunction(plugin: str, function: str, params: dict, authentication: (str|None)):
|
||||||
|
if not authentication:
|
||||||
|
return {"error": "Authentication required"}
|
||||||
|
|
||||||
plugin_module = import_module(plugin.replace("/","."))
|
plugin_module = import_module(plugin.replace("/","."))
|
||||||
if function not in plugin_module.functions:
|
if function not in plugin_module.functions:
|
||||||
return {"error": "Function not found"}
|
return {"error": "Function not found"}
|
||||||
@@ -189,13 +192,13 @@ def runPluginFunction(plugin: str, function: str, params: dict, authentication:
|
|||||||
|
|
||||||
|
|
||||||
def getPluginFunctionInputs(plugin: str, function: str):
|
def getPluginFunctionInputs(plugin: str, function: str):
|
||||||
plugin = import_module(plugin.replace("/","."))
|
imported_plugin = import_module(plugin.replace("/","."))
|
||||||
return plugin.functions[function]["params"]
|
return imported_plugin.functions[function]["params"]
|
||||||
|
|
||||||
|
|
||||||
def getPluginFunctionReturns(plugin: str, function: str):
|
def getPluginFunctionReturns(plugin: str, function: str):
|
||||||
plugin = import_module(plugin.replace("/","."))
|
imported_plugin = import_module(plugin.replace("/","."))
|
||||||
return plugin.functions[function]["returns"]
|
return imported_plugin.functions[function]["returns"]
|
||||||
|
|
||||||
|
|
||||||
def getDomainFunctions():
|
def getDomainFunctions():
|
||||||
|
|||||||
36
render.py
36
render.py
@@ -6,32 +6,7 @@ from domainLookup import punycode_to_emoji
|
|||||||
import os
|
import os
|
||||||
from handywrapper import api
|
from handywrapper import api
|
||||||
import threading
|
import threading
|
||||||
|
import requests
|
||||||
HSD_API = os.getenv("HSD_API")
|
|
||||||
HSD_IP = os.getenv("HSD_IP")
|
|
||||||
if HSD_IP is None:
|
|
||||||
HSD_IP = "localhost"
|
|
||||||
|
|
||||||
HSD_NETWORK = os.getenv("HSD_NETWORK")
|
|
||||||
HSD_WALLET_PORT = 12039
|
|
||||||
HSD_NODE_PORT = 12037
|
|
||||||
|
|
||||||
if not HSD_NETWORK:
|
|
||||||
HSD_NETWORK = "main"
|
|
||||||
else:
|
|
||||||
HSD_NETWORK = HSD_NETWORK.lower()
|
|
||||||
|
|
||||||
if HSD_NETWORK == "simnet":
|
|
||||||
HSD_WALLET_PORT = 15039
|
|
||||||
HSD_NODE_PORT = 15037
|
|
||||||
elif HSD_NETWORK == "testnet":
|
|
||||||
HSD_WALLET_PORT = 13039
|
|
||||||
HSD_NODE_PORT = 13037
|
|
||||||
elif HSD_NETWORK == "regtest":
|
|
||||||
HSD_WALLET_PORT = 14039
|
|
||||||
HSD_NODE_PORT = 14037
|
|
||||||
|
|
||||||
hsd = api.hsd(HSD_API, HSD_IP, HSD_NODE_PORT)
|
|
||||||
|
|
||||||
# Get Explorer URL
|
# Get Explorer URL
|
||||||
TX_EXPLORER_URL = os.getenv("EXPLORER_TX")
|
TX_EXPLORER_URL = os.getenv("EXPLORER_TX")
|
||||||
@@ -96,6 +71,7 @@ actionMap = {
|
|||||||
"UPDATE": "Updated ",
|
"UPDATE": "Updated ",
|
||||||
"REGISTER": "Registered ",
|
"REGISTER": "Registered ",
|
||||||
"RENEW": "Renewed ",
|
"RENEW": "Renewed ",
|
||||||
|
"OPEN": "Opened ",
|
||||||
"BID": "Bid on ",
|
"BID": "Bid on ",
|
||||||
"REVEAL": "Revealed bid for ",
|
"REVEAL": "Revealed bid for ",
|
||||||
"REDEEM": "Redeemed bid for ",
|
"REDEEM": "Redeemed bid for ",
|
||||||
@@ -107,6 +83,7 @@ actionMapPlural = {
|
|||||||
"UPDATE": "Updated multiple domains' records",
|
"UPDATE": "Updated multiple domains' records",
|
||||||
"REGISTER": "Registered multiple domains",
|
"REGISTER": "Registered multiple domains",
|
||||||
"RENEW": "Renewed multiple domains",
|
"RENEW": "Renewed multiple domains",
|
||||||
|
"OPEN": "Opened multiple domains",
|
||||||
"BID": "Bid on multiple domains",
|
"BID": "Bid on multiple domains",
|
||||||
"REVEAL": "Revealed multiple bids",
|
"REVEAL": "Revealed multiple bids",
|
||||||
"REDEEM": "Redeemed multiple bids",
|
"REDEEM": "Redeemed multiple bids",
|
||||||
@@ -558,9 +535,10 @@ def renderDomainAsync(namehash: str) -> None:
|
|||||||
|
|
||||||
if namehash in cache:
|
if namehash in cache:
|
||||||
return
|
return
|
||||||
|
# Fetch the name outside the lock (network call) using hsd.hns.au
|
||||||
|
# name = account.hsd.rpc_getNameByHash(namehash)
|
||||||
|
name = requests.get(f"https://hsd.hns.au/api/v1/namehash/{namehash}").json()
|
||||||
|
|
||||||
# Fetch the name outside the lock (network call)
|
|
||||||
name = hsd.rpc_getNameByHash(namehash)
|
|
||||||
if name["error"] is None:
|
if name["error"] is None:
|
||||||
name = name["result"]
|
name = name["result"]
|
||||||
rendered = renderDomain(name)
|
rendered = renderDomain(name)
|
||||||
@@ -574,7 +552,7 @@ def renderDomainAsync(namehash: str) -> None:
|
|||||||
with open(NAMEHASH_CACHE, 'w') as f:
|
with open(NAMEHASH_CACHE, 'w') as f:
|
||||||
json.dump(cache, f)
|
json.dump(cache, f)
|
||||||
|
|
||||||
return rendered
|
return
|
||||||
else:
|
else:
|
||||||
print(f"Error fetching name for hash {namehash}: {name['error']}", flush=True)
|
print(f"Error fetching name for hash {namehash}: {name['error']}", flush=True)
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ def gunicornServer():
|
|||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
for key, value in self.options.items():
|
for key, value in self.options.items():
|
||||||
if key in self.cfg.settings and value is not None:
|
if key in self.cfg.settings and value is not None: # type: ignore
|
||||||
self.cfg.set(key.lower(), value)
|
self.cfg.set(key.lower(), value) # type: ignore
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
return self.application
|
return self.application
|
||||||
@@ -32,7 +32,7 @@ def gunicornServer():
|
|||||||
gunicorn_app.run()
|
gunicorn_app.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Check if --gunicorn is in the command line arguments
|
# Check if --gunicorn is in the command line arguments
|
||||||
if "--gunicorn" in sys.argv:
|
if "--gunicorn" in sys.argv:
|
||||||
gunicornServer()
|
gunicornServer()
|
||||||
|
|||||||
@@ -69,24 +69,30 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">Node Settings</h4><small>HSD Version: v{{hsd_version}}</small>
|
<h4 class="card-title">Node Settings</h4><small>HSD Version: v{{hsd_version}}</small>
|
||||||
<h6 class="text-muted mb-2 card-subtitle">Settings that affect all wallets</h6>
|
<h6 class="text-muted mb-2 card-subtitle">Settings that affect all wallets</h6><ul class="list-group">
|
||||||
<ul class="list-group">
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<div><a class="btn btn-primary stick-right" role="button" href="/settings/rescan">Rescan</a>
|
||||||
<div><a class="btn btn-primary stick-right" role="button" href="/settings/rescan">Rescan</a>
|
<h3>Rescan</h3><span>Rescan the blockchain for transactions</span>
|
||||||
<h3>Rescan</h3><span>Rescan the blockchain for transactions</span>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<div><a class="btn btn-primary stick-right" role="button" href="/settings/resend">Resend</a>
|
||||||
<div><a class="btn btn-primary stick-right" role="button" href="/settings/resend">Resend</a>
|
<h3>Resend unconfirmed transactions</h3><span>Resend any transactions that haven't been mined yet.</span>
|
||||||
<h3>Resend unconfirmed transactions</h3><span>Resend any transactions that haven't been mined yet.</span>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<div><a class="btn btn-primary stick-right" role="button" href="/settings/zap">Zap</a>
|
||||||
<div><a class="btn btn-primary stick-right" role="button" href="/settings/zap">Zap</a>
|
<h3>Delete unconfirmed transactions</h3><span>This will only remove pending tx from the wallet older than 20 minutes (~ 2 blocks)</span>
|
||||||
<h3>Delete unconfirmed transactions</h3><span>This will only remove pending tx from the wallet older than 20 minutes (~ 2 blocks)</span>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
{% if internal %}
|
||||||
</ul>
|
<li class="list-group-item">
|
||||||
|
<div><a class="btn btn-primary stick-right" role="button" href="/settings/restart">Restart Node</a>
|
||||||
|
<h3>Restart Internal Node</h3><span>This will attempt to restart the HSD node</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
47
templates/welcome.html
Normal file
47
templates/welcome.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en-au" style="height: 100%;">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Welcome to FireWallet</title>
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="900x768" href="/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/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i&display=swap">
|
||||||
|
<link rel="stylesheet" href="/assets/css/styles.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="d-flex align-items-center bg-gradient-primary" style="height: 100%;">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-9 col-lg-12 col-xl-10">
|
||||||
|
<h1 class="text-center" style="color: var(--bs-danger);background: var(--bs-primary);">{{error}}</h1>
|
||||||
|
<div class="card shadow-lg my-5 o-hidden border-0" style="padding-top: 50px;padding-bottom: 50px;">
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 d-none d-lg-flex">
|
||||||
|
<div class="flex-grow-1 bg-login-image" style="background: url("/assets/img/favicon.png") center / contain no-repeat;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="text-center p-5">
|
||||||
|
<div class="text-center">
|
||||||
|
<h4 class="mb-4">Welcome to FireWallet!</h4>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group-vertical btn-group-lg gap-1" role="group"><a class="btn btn-primary" role="button" href="/register">Create a new wallet</a><a class="btn btn-primary" role="button" href="/import-wallet">Import an existing wallet</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="/assets/js/script.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user