2024-01-25 23:15:59 +11:00
import json
2024-01-26 03:51:52 +11:00
import random
2023-12-28 16:58:11 +11:00
from flask import Flask , make_response , redirect , request , jsonify , render_template , send_from_directory , send_file
2023-12-28 13:34:48 +11:00
import os
import dotenv
import requests
import account as account_module
import render
2023-12-28 16:04:45 +11:00
import re
2023-12-28 16:58:11 +11:00
from flask_qrcode import QRcode
2023-12-28 18:04:38 +11:00
import domainLookup
2024-01-25 23:15:59 +11:00
import urllib . parse
2024-02-02 21:40:02 +11:00
import importlib
2023-12-28 13:34:48 +11:00
dotenv . load_dotenv ( )
app = Flask ( __name__ )
2023-12-28 16:58:11 +11:00
qrcode = QRcode ( app )
2023-12-28 13:34:48 +11:00
2023-12-29 12:50:15 +11:00
# Change this if network fees change
fees = 0.02
2024-01-26 03:51:52 +11:00
revokeCheck = random . randint ( 100000 , 999999 )
2023-12-29 12:50:15 +11:00
2024-02-01 23:41:22 +11:00
theme = os . getenv ( " theme " )
2023-12-28 13:34:48 +11:00
@app.route ( ' / ' )
def index ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
2023-12-28 16:04:45 +11:00
if not account :
return redirect ( " /logout " )
2023-12-28 13:34:48 +11:00
balance = account_module . getBalance ( account )
available = balance [ ' available ' ]
total = balance [ ' total ' ]
# Add commas to the numbers
available = " {:,} " . format ( available )
total = " {:,} " . format ( total )
pending = account_module . getPendingTX ( account )
domains = account_module . getDomains ( account )
2024-01-25 18:53:04 +11:00
# Sort
sort = request . args . get ( " sort " )
if sort == None :
sort = " domain "
sort = sort . lower ( )
sort_price = " "
sort_price_next = " ⬇ "
sort_expiry = " "
sort_expiry_next = " ⬇ "
sort_domain = " "
sort_domain_next = " ⬇ "
reverse = False
direction = request . args . get ( " direction " )
if direction == None :
direction = " ⬇ "
if direction == " ⬆ " :
reverse = True
if sort == " expiry " :
# Sort by next expiry
domains = sorted ( domains , key = lambda k : k [ ' renewal ' ] , reverse = reverse )
sort_expiry = direction
sort_expiry_next = reverseDirection ( direction )
elif sort == " price " :
# Sort by price
domains = sorted ( domains , key = lambda k : k [ ' value ' ] , reverse = reverse )
sort_price = direction
sort_price_next = reverseDirection ( direction )
else :
# Sort by domain
domains = sorted ( domains , key = lambda k : k [ ' name ' ] , reverse = reverse )
sort_domain = direction
sort_domain_next = reverseDirection ( direction )
2023-12-28 16:04:45 +11:00
domain_count = len ( domains )
2023-12-28 13:34:48 +11:00
domains = render . domains ( domains )
2023-12-28 16:04:45 +11:00
2023-12-28 13:34:48 +11:00
return render_template ( " index.html " , account = account , available = available ,
2023-12-29 11:42:20 +11:00
total = total , pending = pending , domains = domains ,
2024-01-25 18:53:04 +11:00
domain_count = domain_count , sync = account_module . getNodeSync ( ) ,
sort_price = sort_price , sort_expiry = sort_expiry ,
sort_domain = sort_domain , sort_price_next = sort_price_next ,
sort_expiry_next = sort_expiry_next , sort_domain_next = sort_domain_next )
2023-12-28 18:04:38 +11:00
2024-01-25 18:53:04 +11:00
def reverseDirection ( direction : str ) :
if direction == " ⬆ " :
return " ⬇ "
else :
return " ⬆ "
2023-12-28 18:04:38 +11:00
#region Transactions
2023-12-28 13:34:48 +11:00
@app.route ( ' /tx ' )
def transactions ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
# Get the transactions
transactions = account_module . getTransactions ( account )
transactions = render . transactions ( transactions )
2023-12-29 11:42:20 +11:00
return render_template ( " tx.html " , account = account , sync = account_module . getNodeSync ( ) ,
tx = transactions )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
@app.route ( ' /send ' )
def send_page ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
account = account_module . check_account ( request . cookies . get ( " account " ) )
max = account_module . getBalance ( account ) [ ' available ' ]
2023-12-29 12:50:15 +11:00
# Subtract approx fee
max = max - fees
2023-12-28 16:58:11 +11:00
max = round ( max , 2 )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
message = ' '
address = ' '
amount = ' '
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
if ' message ' in request . args :
message = request . args . get ( " message " )
if ' address ' in request . args :
address = request . args . get ( " address " )
if ' amount ' in request . args :
amount = request . args . get ( " amount " )
2023-12-29 11:42:20 +11:00
return render_template ( " send.html " , account = account , sync = account_module . getNodeSync ( ) ,
max = max , message = message , address = address , amount = amount )
2023-12-28 16:04:45 +11:00
@app.route ( ' /send ' , methods = [ " POST " ] )
def send ( ) :
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
# Get the address and amount
address = request . form . get ( " address " )
amount = request . form . get ( " amount " )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
if address is None or amount is None :
return redirect ( " /send?message=Invalid address or amount&address= " + address + " &amount= " + amount )
address_check = account_module . check_address ( address , True , True )
if not address_check :
return redirect ( " /send?message=Invalid address&address= " + address + " &amount= " + amount )
address = address_check
# Check if the amount is valid
if re . match ( r " ^ \ d+( \ . \ d+)?$ " , amount ) is None :
return redirect ( " /send?message=Invalid amount&address= " + address + " &amount= " + amount )
# Check if the amount is valid
amount = float ( amount )
if amount < = 0 :
return redirect ( " /send?message=Invalid amount&address= " + address + " &amount= " + str ( amount ) )
2023-12-29 12:50:15 +11:00
if amount > account_module . getBalance ( account ) [ ' available ' ] - fees :
2023-12-28 16:04:45 +11:00
return redirect ( " /send?message=Not enough funds to transfer&address= " + address + " &amount= " + str ( amount ) )
2024-01-25 18:53:04 +11:00
toAddress = address
if request . form . get ( ' address ' ) != address :
toAddress = request . form . get ( ' address ' ) + " <br> " + 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 " This will cost { amount } HNS + mining fees and is not able to be undone. "
cancel = f " /send "
confirm = f " /send/confirm?address= { address } &amount= { amount } "
return render_template ( " confirm.html " , account = account_module . check_account ( request . cookies . get ( " account " ) ) ,
sync = account_module . getNodeSync ( ) , action = action ,
content = content , cancel = cancel , confirm = confirm )
@app.route ( ' /send/confirm ' )
def sendConfirmed ( ) :
address = request . args . get ( " address " )
amount = float ( request . args . get ( " amount " ) )
2023-12-28 16:04:45 +11:00
response = account_module . send ( request . cookies . get ( " account " ) , address , amount )
if ' error ' in response :
return redirect ( " /send?message= " + response [ ' error ' ] + " &address= " + address + " &amount= " + str ( amount ) )
return redirect ( " /success?tx= " + response [ ' tx ' ] )
2024-01-25 18:53:04 +11:00
2023-12-28 16:58:11 +11:00
@app.route ( ' /receive ' )
def receive ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
address = account_module . getAddress ( account )
2023-12-29 11:42:20 +11:00
return render_template ( " receive.html " , account = account , sync = account_module . getNodeSync ( ) ,
address = address )
2023-12-28 16:04:45 +11:00
@app.route ( ' /success ' )
def success ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
tx = request . args . get ( " tx " )
2023-12-29 11:42:20 +11:00
return render_template ( " success.html " , account = account , sync = account_module . getNodeSync ( ) ,
tx = tx )
2023-12-28 13:34:48 +11:00
2023-12-28 16:04:45 +11:00
@app.route ( ' /checkaddress ' )
def check_address ( ) :
address = request . args . get ( " address " )
if address is None :
return jsonify ( { " result " : " Invalid address " } )
return jsonify ( { " result " : account_module . check_address ( address ) } )
2023-12-28 18:04:38 +11:00
#endregion
#region Domains
@app.route ( ' /search ' )
def search ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
search_term = request . args . get ( " q " )
search_term = search_term . lower ( ) . strip ( )
2023-12-29 11:42:20 +11:00
# Convert emoji to punycode
search_term = domainLookup . emoji_to_punycode ( search_term )
2023-12-28 18:04:38 +11:00
if len ( search_term ) == 0 :
return redirect ( " / " )
2023-12-29 11:42:20 +11:00
2023-12-28 18:04:38 +11:00
domain = account_module . getDomain ( search_term )
if ' error ' in domain :
2023-12-29 11:42:20 +11:00
return render_template ( " search.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = domain [ ' error ' ] )
2023-12-28 18:04:38 +11:00
if domain [ ' info ' ] is None :
2023-12-29 11:42:20 +11:00
return render_template ( " search.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = search_term ,
state = " AVAILABLE " , next = " Available Now " )
2023-12-28 18:04:38 +11:00
state = domain [ ' info ' ] [ ' state ' ]
if state == ' CLOSED ' :
2024-01-26 17:17:01 +11:00
if domain [ ' info ' ] [ ' registered ' ] :
2023-12-28 18:04:38 +11:00
state = ' REGISTERED '
expires = domain [ ' info ' ] [ ' stats ' ] [ ' daysUntilExpire ' ]
next = f " Expires in ~ { expires } days "
2024-01-26 17:17:01 +11:00
else :
state = ' AVAILABLE '
next = " Available Now "
elif state == " REVOKED " :
next = " Available Now "
2023-12-29 11:42:20 +11:00
elif state == ' OPENING ' :
next = " Bidding opens in ~ " + str ( domain [ ' info ' ] [ ' stats ' ] [ ' blocksUntilBidding ' ] ) + " blocks "
elif state == ' BIDDING ' :
next = " Reveal in ~ " + str ( domain [ ' info ' ] [ ' stats ' ] [ ' blocksUntilReveal ' ] ) + " blocks "
elif state == ' REVEAL ' :
next = " Reveal ends in ~ " + str ( domain [ ' info ' ] [ ' stats ' ] [ ' blocksUntilClose ' ] ) + " blocks "
2023-12-28 18:04:38 +11:00
domain_info = domainLookup . niami_info ( search_term )
owner = ' Unknown '
dns = [ ]
txs = [ ]
if domain_info :
owner = domain_info [ ' owner ' ]
dns = domain_info [ ' dns ' ]
txs = domain_info [ ' txs ' ]
own_domains = account_module . getDomains ( account )
own_domains = [ x [ ' name ' ] for x in own_domains ]
own_domains = [ x . lower ( ) for x in own_domains ]
if search_term in own_domains :
owner = " You "
dns = render . dns ( dns )
txs = render . txs ( txs )
2023-12-29 11:42:20 +11:00
return render_template ( " search.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = domain [ ' info ' ] [ ' name ' ] ,
raw = domain , state = state , next = next , owner = owner ,
dns = dns , txs = txs )
2023-12-28 18:04:38 +11:00
2023-12-28 18:31:44 +11:00
@app.route ( ' /manage/<domain> ' )
2024-01-25 23:15:59 +11:00
def manage ( domain : str ) :
2023-12-28 18:31:44 +11:00
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
2023-12-28 18:04:38 +11:00
2023-12-28 18:31:44 +11:00
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
domain = domain . lower ( )
own_domains = account_module . getDomains ( account )
own_domains = [ x [ ' name ' ] for x in own_domains ]
own_domains = [ x . lower ( ) for x in own_domains ]
if domain not in own_domains :
return redirect ( " /search?q= " + domain )
2023-12-28 18:04:38 +11:00
2023-12-28 18:31:44 +11:00
domain_info = account_module . getDomain ( domain )
if ' error ' in domain_info :
2023-12-29 11:42:20 +11:00
return render_template ( " manage.html " , account = account , sync = account_module . getNodeSync ( ) ,
domain = domain , error = domain_info [ ' error ' ] )
2023-12-28 18:31:44 +11:00
expiry = domain_info [ ' info ' ] [ ' stats ' ] [ ' daysUntilExpire ' ]
dns = account_module . getDNS ( domain )
2024-01-25 23:15:59 +11:00
raw_dns = str ( dns ) . replace ( " ' " , ' " ' )
2023-12-28 18:31:44 +11:00
dns = render . dns ( dns )
2024-01-26 03:51:52 +11:00
errorMessage = request . args . get ( " error " )
if errorMessage == None :
errorMessage = " "
address = request . args . get ( " address " )
if address == None :
address = " "
finalize_time = " "
# Check if the domain is in transfer
if domain_info [ ' info ' ] [ ' transfer ' ] != 0 :
current_block = account_module . getBlockHeight ( )
finalize_valid = domain_info [ ' info ' ] [ ' transfer ' ] + 288
finalize_blocks = finalize_valid - current_block
if finalize_blocks > 0 :
finalize_time = " in " + str ( finalize_blocks ) + " blocks (~ " + str ( round ( finalize_blocks / 6 ) ) + " hours) "
else :
finalize_time = " now "
2023-12-28 18:31:44 +11:00
2024-02-05 22:40:13 +11:00
plugins = " <div class= ' container-fluid ' > "
# Execute domain plugins
plugin_links = os . listdir ( " plugins " )
for plugin in plugin_links :
if os . path . isdir ( " plugins/ " + plugin ) :
module = importlib . import_module ( " plugins. " + plugin + " .main " )
moduleFunctions = module . listFunctions ( )
for moduleFunction in moduleFunctions :
data = moduleFunctions [ moduleFunction ]
if " type " in data :
if data [ " type " ] == " domain " :
# Run function
print ( data )
functionOutput = module . runFunction ( moduleFunction , { " domain " : domain } , account_module . check_account ( request . cookies . get ( " account " ) ) )
print ( functionOutput )
plugins + = render . plugin_output ( functionOutput , data [ ' returns ' ] )
plugins + = " </div> "
2023-12-29 11:42:20 +11:00
return render_template ( " manage.html " , account = account , sync = account_module . getNodeSync ( ) ,
2024-01-26 03:51:52 +11:00
error = errorMessage , address = address ,
domain = domain , expiry = expiry , dns = dns ,
raw_dns = urllib . parse . quote ( raw_dns ) ,
2024-02-05 22:40:13 +11:00
finalize_time = finalize_time , plugins = plugins )
2024-01-26 03:51:52 +11:00
@app.route ( ' /manage/<domain>/finalize ' )
def finalize ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
print ( domain )
response = account_module . finalize ( request . cookies . get ( " account " ) , domain )
2024-02-04 16:55:28 +11:00
if response [ ' error ' ] != None :
2024-01-26 03:51:52 +11:00
print ( response )
return redirect ( " /manage/ " + domain + " ?error= " + response [ ' error ' ] [ ' message ' ] )
2024-02-04 16:55:28 +11:00
return redirect ( " /success?tx= " + response [ ' result ' ] [ ' hash ' ] )
2024-01-26 03:51:52 +11:00
@app.route ( ' /manage/<domain>/cancel ' )
def cancelTransfer ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
print ( domain )
response = account_module . cancelTransfer ( request . cookies . get ( " account " ) , domain )
if ' error ' in response :
if response [ ' error ' ] != None :
print ( response )
return redirect ( " /manage/ " + domain + " ?error= " + response [ ' error ' ] [ ' message ' ] )
return redirect ( " /success?tx= " + response [ ' result ' ] [ ' hash ' ] )
@app.route ( ' /manage/<domain>/revoke ' )
def revokeInit ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
content = f " Are you sure you want to revoke { domain } /?<br> "
content + = f " This will return the domain to the auction pool and you will lose any funds spent on the domain.<br> "
content + = f " This cannot be undone after the transaction is sent.<br><br> "
content + = f " Please enter your password to confirm. "
cancel = f " /manage/ { domain } "
confirm = f " /manage/ { domain } /revoke/confirm "
action = f " Revoke { domain } / "
return render_template ( " confirm-password.html " , account = account_module . check_account ( request . cookies . get ( " account " ) ) ,
sync = account_module . getNodeSync ( ) , action = action ,
content = content , cancel = cancel , confirm = confirm , check = revokeCheck )
@app.route ( ' /manage/<domain>/revoke/confirm ' , methods = [ " POST " ] )
def revokeConfirm ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
password = request . form . get ( " password " )
check = request . form . get ( " check " )
if check != str ( revokeCheck ) :
return redirect ( " /manage/ " + domain + " ?error=An error occurred. Please try again. " )
response = account_module . check_password ( request . cookies . get ( " account " ) , password )
if response == False :
return redirect ( " /manage/ " + domain + " ?error=Invalid password " )
response = account_module . revoke ( request . cookies . get ( " account " ) , domain )
if ' error ' in response :
2024-01-26 17:17:01 +11:00
if response [ ' error ' ] != None :
print ( response )
return redirect ( " /manage/ " + domain + " ?error= " + response [ ' error ' ] [ ' message ' ] )
2023-12-28 18:31:44 +11:00
2024-01-26 03:51:52 +11:00
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-28 18:04:38 +11:00
2023-12-28 18:31:44 +11:00
@app.route ( ' /manage/<domain>/renew ' )
2024-01-25 23:15:59 +11:00
def renew ( domain : str ) :
2023-12-28 18:31:44 +11:00
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
response = account_module . renewDomain ( request . cookies . get ( " account " ) , domain )
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-28 18:04:38 +11:00
2024-01-25 23:15:59 +11:00
@app.route ( ' /manage/<domain>/edit ' )
def editPage ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
domain = domain . lower ( )
own_domains = account_module . getDomains ( account )
own_domains = [ x [ ' name ' ] for x in own_domains ]
own_domains = [ x . lower ( ) for x in own_domains ]
if domain not in own_domains :
return redirect ( " /search?q= " + domain )
user_edits = request . args . get ( " dns " )
if user_edits != None :
dns = urllib . parse . unquote ( user_edits )
else :
dns = account_module . getDNS ( domain )
dns = json . loads ( dns )
# Check if new records have been added
dnsType = request . args . get ( " type " )
dnsValue = request . args . get ( " value " )
if dnsType != None and dnsValue != None :
if dnsType != " DS " :
dns . append ( { " type " : dnsType , " value " : dnsValue } )
else :
# Verify the DS record
ds = dnsValue . split ( " " )
if len ( ds ) != 4 :
raw_dns = str ( dns ) . replace ( " ' " , ' " ' )
return redirect ( " /manage/ " + domain + " /edit?dns= " + urllib . parse . quote ( str ( raw_dns ) ) + " &error=Invalid DS record " )
try :
ds [ 0 ] = int ( ds [ 0 ] )
ds [ 1 ] = int ( ds [ 1 ] )
ds [ 2 ] = int ( ds [ 2 ] )
except :
raw_dns = str ( dns ) . replace ( " ' " , ' " ' )
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 = json . dumps ( dns ) . replace ( " ' " , ' " ' )
return redirect ( " /manage/ " + domain + " /edit?dns= " + urllib . parse . quote ( dns ) )
raw_dns = str ( dns ) . replace ( " ' " , ' " ' )
dns = render . dns ( dns , True )
errorMessage = request . args . get ( " error " )
if errorMessage == None :
errorMessage = " "
return render_template ( " edit.html " , account = account , sync = account_module . getNodeSync ( ) ,
domain = domain , error = errorMessage ,
dns = dns , raw_dns = urllib . parse . quote ( raw_dns ) )
@app.route ( ' /manage/<domain>/edit/save ' )
def editSave ( domain : str ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
dns = request . args . get ( " dns " )
raw_dns = dns
dns = urllib . parse . unquote ( dns )
response = account_module . setDNS ( request . cookies . get ( " account " ) , domain , dns )
if ' error ' in response :
print ( response )
return redirect ( " /manage/ " + domain + " /edit?dns= " + raw_dns + " &error= " + str ( response [ ' error ' ] ) )
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-29 12:42:07 +11:00
2024-01-26 03:51:52 +11:00
@app.route ( ' /manage/<domain>/transfer ' )
def transfer ( domain ) :
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
# Get the address and amount
address = request . args . get ( " address " )
if address is None :
return redirect ( " /manage/ " + domain + " ?error=Invalid address " )
address_check = account_module . check_address ( address , True , True )
if not address_check :
return redirect ( " /send?message=Invalid address&address= " + address )
address = address_check
toAddress = address
if request . form . get ( ' address ' ) != address :
toAddress = request . args . get ( ' address ' ) + " <br> " + 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 " This requires sending a finalize transaction 2 days after the transfer is initiated. "
cancel = f " /manage/ { domain } ?address= { address } "
confirm = f " /manage/ { domain } /transfer/confirm?address= { address } "
return render_template ( " confirm.html " , account = account_module . check_account ( request . cookies . get ( " account " ) ) ,
sync = account_module . getNodeSync ( ) , action = action ,
content = content , cancel = cancel , confirm = confirm )
@app.route ( ' /manage/<domain>/transfer/confirm ' )
def transferConfirm ( domain ) :
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
# Get the address and amount
address = request . args . get ( " address " )
response = account_module . transfer ( request . cookies . get ( " account " ) , domain , address )
if ' error ' in response :
return redirect ( " /manage/ " + domain + " ?error= " + response [ ' error ' ] )
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-29 12:42:07 +11:00
@app.route ( ' /auction/<domain> ' )
def auction ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
search_term = domain . lower ( ) . strip ( )
# Convert emoji to punycode
search_term = domainLookup . emoji_to_punycode ( search_term )
if len ( search_term ) == 0 :
return redirect ( " / " )
domainInfo = account_module . getDomain ( search_term )
if ' error ' in domainInfo :
return render_template ( " auction.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = domainInfo [ ' error ' ] )
if domainInfo [ ' info ' ] is None :
next_action = f ' <a href= " /auction/ { domain } /open " >Open Auction</a> '
return render_template ( " auction.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = search_term , next_action = next_action ,
state = " AVAILABLE " , next = " Open Auction " )
state = domainInfo [ ' info ' ] [ ' state ' ]
next_action = ' '
bids = account_module . getBids ( account , search_term )
if bids == [ ] :
bids = " No bids found "
next_action = f ' <a href= " /auction/ { domain } /scan " >Rescan Auction</a> '
else :
2023-12-29 13:57:20 +11:00
reveals = account_module . getReveals ( account , search_term )
for reveal in reveals :
# Get TX
revealInfo = account_module . getRevealTX ( reveal )
reveal [ ' bid ' ] = revealInfo
print ( revealInfo )
bids = render . bids ( bids , reveals )
2023-12-29 12:42:07 +11:00
if state == ' CLOSED ' :
if not domainInfo [ ' info ' ] [ ' registered ' ] :
state = ' AVAILABLE '
next = " Available Now "
next_action = f ' <a href= " /auction/ { domain } /open " >Open Auction</a> '
else :
state = ' REGISTERED '
expires = domainInfo [ ' info ' ] [ ' stats ' ] [ ' daysUntilExpire ' ]
next = f " Expires in ~ { expires } days "
own_domains = account_module . getDomains ( account )
own_domains = [ x [ ' name ' ] for x in own_domains ]
own_domains = [ x . lower ( ) for x in own_domains ]
if search_term in own_domains :
next_action = f ' <a href= " /manage/ { domain } " >Manage</a> '
2024-01-26 17:17:01 +11:00
elif state == " REVOKED " :
next = " Available Now "
next_action = f ' <a href= " /auction/ { domain } /open " >Open Auction</a> '
2023-12-29 12:42:07 +11:00
elif state == ' OPENING ' :
next = " Bidding opens in ~ " + str ( domainInfo [ ' info ' ] [ ' stats ' ] [ ' blocksUntilBidding ' ] ) + " blocks "
elif state == ' BIDDING ' :
next = " Reveal in ~ " + str ( domainInfo [ ' info ' ] [ ' stats ' ] [ ' blocksUntilReveal ' ] ) + " blocks "
elif state == ' REVEAL ' :
next = " Reveal ends in ~ " + str ( domainInfo [ ' info ' ] [ ' stats ' ] [ ' blocksUntilClose ' ] ) + " blocks "
next_action = f ' <a href= " /auction/ { domain } /reveal " >Reveal All</a> '
message = ' '
if ' message ' in request . args :
message = request . args . get ( " message " )
return render_template ( " auction.html " , account = account , sync = account_module . getNodeSync ( ) ,
search_term = search_term , domain = domainInfo [ ' info ' ] [ ' name ' ] ,
raw = domainInfo , state = state , next = next ,
next_action = next_action , bids = bids , error = message )
@app.route ( ' /auction/<domain>/scan ' )
def rescan_auction ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
domain = domain . lower ( )
response = account_module . rescan_auction ( account , domain )
print ( response )
return redirect ( " /auction/ " + domain )
@app.route ( ' /auction/<domain>/bid ' )
def bid ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
2023-12-29 14:24:43 +11:00
bid = request . args . get ( " bid " )
blind = request . args . get ( " blind " )
2024-01-03 02:05:48 +11:00
if bid == " " :
2023-12-29 14:24:43 +11:00
bid = 0
2024-01-03 02:05:48 +11:00
if blind == " " :
2023-12-29 14:24:43 +11:00
blind = 0
if bid + blind == 0 :
return redirect ( " /auction/ " + domain + " ?message=Invalid bid amount " )
2023-12-29 12:42:07 +11:00
# Show confirm page
2023-12-29 14:24:43 +11:00
total = float ( bid ) + float ( blind )
2023-12-29 12:42:07 +11:00
action = f " Bid on { domain } / "
content = f " Are you sure you want to bid on { domain } /? "
2024-01-25 18:53:04 +11:00
content + = " You are about to bid with the following details:<br><br> "
2023-12-29 12:42:07 +11:00
content + = f " Bid: { request . args . get ( ' bid ' ) } HNS<br> "
content + = f " Blind: { request . args . get ( ' blind ' ) } HNS<br> "
content + = f " Total: { total } HNS (excluding fees)<br><br> "
cancel = f " /auction/ { domain } "
confirm = f " /auction/ { domain } /bid/confirm?bid= { request . args . get ( ' bid ' ) } &blind= { request . args . get ( ' blind ' ) } "
return render_template ( " confirm.html " , account = account_module . check_account ( request . cookies . get ( " account " ) ) ,
sync = account_module . getNodeSync ( ) , action = action ,
domain = domain , content = content , cancel = cancel , confirm = confirm )
@app.route ( ' /auction/<domain>/bid/confirm ' )
def bid_confirm ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
# Send the bid
response = account_module . bid ( request . cookies . get ( " account " ) , domain ,
float ( request . args . get ( ' bid ' ) ) ,
float ( request . args . get ( ' blind ' ) ) )
print ( response )
if ' error ' in response :
2023-12-29 14:24:43 +11:00
return redirect ( " /auction/ " + domain + " ?message= " + response [ ' error ' ] [ ' message ' ] )
2023-12-29 12:42:07 +11:00
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-29 12:50:15 +11:00
@app.route ( ' /auction/<domain>/open ' )
def open_auction ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
response = account_module . openAuction ( request . cookies . get ( " account " ) , domain )
2024-01-26 17:17:01 +11:00
if ' error ' in response :
if response [ ' error ' ] != None :
return redirect ( " /auction/ " + domain + " ?message= " + response [ ' error ' ] [ ' message ' ] )
print ( response )
2023-12-29 12:50:15 +11:00
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2023-12-29 14:24:43 +11:00
@app.route ( ' /auction/<domain>/reveal ' )
def reveal_auction ( domain ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
if not account_module . check_account ( request . cookies . get ( " account " ) ) :
return redirect ( " /logout " )
domain = domain . lower ( )
response = account_module . revealAuction ( request . cookies . get ( " account " ) , domain )
if ' error ' in response :
return redirect ( " /auction/ " + domain + " ?message= " + response [ ' error ' ] [ ' message ' ] )
return redirect ( " /success?tx= " + response [ ' hash ' ] )
2024-02-02 21:40:02 +11:00
#endregion
#region Settings
2024-01-29 15:07:43 +11:00
@app.route ( ' /settings ' )
def settings ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
error = request . args . get ( " error " )
if error == None :
error = " "
success = request . args . get ( " success " )
if success == None :
success = " "
return render_template ( " settings.html " , account = account , sync = account_module . getNodeSync ( ) ,
error = error , success = success )
@app.route ( ' /settings/<action> ' )
def settings_action ( action ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
if action == " rescan " :
resp = account_module . rescan ( )
if ' error ' in resp :
return redirect ( " /settings?error= " + str ( resp [ ' error ' ] ) )
return redirect ( " /settings?success=Resent transactions " )
elif action == " resend " :
resp = account_module . resendTXs ( )
if ' error ' in resp :
return redirect ( " /settings?error= " + str ( resp [ ' error ' ] ) )
return redirect ( " /settings?success=Resent transactions " )
elif action == " zap " :
resp = account_module . zapTXs ( request . cookies . get ( " account " ) )
if ' error ' in resp :
return redirect ( " /settings?error= " + str ( resp [ ' error ' ] ) )
return redirect ( " /settings?success=Zapped transactions " )
elif action == " xpub " :
return render_template ( " message.html " , account = account , sync = account_module . getNodeSync ( ) ,
title = " xPub Key " , content = account_module . getxPub ( request . cookies . get ( " account " ) ) )
return redirect ( " /settings?error=Invalid action " )
#endregion
2023-12-28 18:04:38 +11:00
2023-12-28 13:34:48 +11:00
#region Account
@app.route ( ' /login ' )
def login ( ) :
2024-01-29 15:19:38 +11:00
wallets = account_module . listWallets ( )
wallets = render . wallets ( wallets )
2023-12-28 13:34:48 +11:00
if ' message ' in request . args :
2023-12-29 11:42:20 +11:00
return render_template ( " login.html " , sync = account_module . getNodeSync ( ) ,
2024-01-29 15:19:38 +11:00
error = request . args . get ( " message " ) , wallets = wallets )
2023-12-28 13:34:48 +11:00
2024-01-29 15:19:38 +11:00
return render_template ( " login.html " , sync = account_module . getNodeSync ( ) ,
wallets = wallets )
2023-12-28 13:34:48 +11:00
@app.route ( ' /login ' , methods = [ " POST " ] )
def login_post ( ) :
# Get the account and password
account = request . form . get ( " account " )
password = request . form . get ( " password " )
# Check if the account is valid
if account . count ( " : " ) > 0 :
2023-12-29 11:42:20 +11:00
return render_template ( " login.html " , sync = account_module . getNodeSync ( ) ,
error = " Invalid account " )
2023-12-28 13:34:48 +11:00
account = account + " : " + password
# Check if the account is valid
if not account_module . check_account ( account ) :
2023-12-29 11:42:20 +11:00
return render_template ( " login.html " , sync = account_module . getNodeSync ( ) ,
error = " Invalid account " )
2023-12-28 13:34:48 +11:00
# Set the cookie
response = make_response ( redirect ( " / " ) )
response . set_cookie ( " account " , account )
return response
@app.route ( ' /logout ' )
def logout ( ) :
response = make_response ( redirect ( " /login " ) )
response . set_cookie ( " account " , " " , expires = 0 )
return response
2024-01-29 15:07:43 +11:00
@app.route ( ' /register ' , methods = [ " POST " ] )
def register ( ) :
# Get the account and password
account = request . form . get ( " name " )
password = request . form . get ( " password " )
repeatPassword = request . form . get ( " password_repeat " )
# Check if the passwords match
if password != repeatPassword :
return render_template ( " register.html " ,
error = " Passwords do not match " ,
name = account , password = password , password_repeat = repeatPassword )
# Check if the account is valid
if account . count ( " : " ) > 0 :
return render_template ( " register.html " ,
error = " Invalid account " ,
name = account , password = password , password_repeat = repeatPassword )
# List wallets
wallets = account_module . listWallets ( )
if account in wallets :
return render_template ( " register.html " ,
error = " Account already exists " ,
name = account , password = password , password_repeat = repeatPassword )
# Create the account
response = account_module . createWallet ( account , password )
if ' error ' in response :
return render_template ( " register.html " ,
error = response [ ' error ' ] ,
name = account , password = password , password_repeat = repeatPassword )
# Set the cookie
response = make_response ( render_template ( " message.html " , sync = account_module . getNodeSync ( ) ,
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 )
return response
2024-02-04 16:55:28 +11:00
@app.route ( ' /import-wallet ' , methods = [ " POST " ] )
def import_wallet ( ) :
# Get the account and password
account = request . form . get ( " name " )
password = request . form . get ( " password " )
repeatPassword = request . form . get ( " password_repeat " )
seed = request . form . get ( " seed " )
# Check if the passwords match
if password != repeatPassword :
return render_template ( " import-wallet.html " ,
error = " Passwords do not match " ,
name = account , password = password , password_repeat = repeatPassword ,
seed = seed )
# Check if the account is valid
if account . count ( " : " ) > 0 :
return render_template ( " import-wallet.html " ,
error = " Invalid account " ,
name = account , password = password , password_repeat = repeatPassword ,
seed = seed )
# List wallets
wallets = account_module . listWallets ( )
if account in wallets :
return render_template ( " import-wallet.html " ,
error = " Account already exists " ,
name = account , password = password , password_repeat = repeatPassword ,
seed = seed )
# Create the account
response = account_module . importWallet ( account , password , seed )
if ' error ' in response :
return render_template ( " import-wallet.html " ,
error = response [ ' error ' ] ,
name = account , password = password , password_repeat = repeatPassword ,
seed = seed )
# Set the cookie
response = make_response ( redirect ( " / " ) )
response . set_cookie ( " account " , account + " : " + password )
return response
2024-01-26 03:51:52 +11:00
@app.route ( ' /report ' )
def report ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
return jsonify ( account_module . generateReport ( account ) )
2023-12-28 13:34:48 +11:00
#endregion
2024-02-02 21:40:02 +11:00
#region Plugins
@app.route ( ' /plugins ' )
def plugins_index ( ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
plugin_links = os . listdir ( " plugins " )
plugins = [ ]
for plugin in plugin_links :
if os . path . isdir ( " plugins/ " + plugin ) :
if os . path . isfile ( " plugins/ " + plugin + " / " + plugin + " .json " ) :
with open ( " plugins/ " + plugin + " / " + plugin + " .json " ) as f :
data = json . load ( f )
data [ ' link ' ] = plugin
if ' name ' not in data :
data [ ' name ' ] = plugin
if ' description ' not in data :
data [ ' description ' ] = " No description provided "
plugins . append ( data )
plugins = render . plugins ( plugins )
return render_template ( " plugins.html " , account = account , sync = account_module . getNodeSync ( ) ,
plugins = plugins )
@app.route ( ' /plugin/<plugin> ' )
def plugin ( plugin ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
if not os . path . isdir ( " plugins/ " + plugin ) :
return redirect ( " /plugins " )
if not os . path . isfile ( " plugins/ " + plugin + " / " + plugin + " .json " ) :
return redirect ( " /plugins " )
with open ( " plugins/ " + plugin + " / " + plugin + " .json " ) as f :
data = json . load ( f )
data [ ' link ' ] = plugin
if ' name ' not in data :
data [ ' name ' ] = plugin
if ' description ' not in data :
data [ ' description ' ] = " No description provided "
functions = [ ]
if os . path . isfile ( " plugins/ " + plugin + " /main.py " ) :
# Get plugin/main.py listfunctions()
print ( " Loading plugin: " + plugin )
module = importlib . import_module ( " plugins. " + plugin + " .main " )
functions = module . listFunctions ( )
functions = render . plugin_functions ( functions , plugin )
error = request . args . get ( " error " )
if error == None :
error = " "
return render_template ( " plugin.html " , account = account , sync = account_module . getNodeSync ( ) ,
name = data [ ' name ' ] , description = data [ ' description ' ] , functions = functions ,
error = error )
@app.route ( ' /plugin/<plugin>/<function> ' , methods = [ " POST " ] )
def plugin_function ( plugin , function ) :
# Check if the user is logged in
if request . cookies . get ( " account " ) is None :
return redirect ( " /login " )
account = account_module . check_account ( request . cookies . get ( " account " ) )
if not account :
return redirect ( " /logout " )
if not os . path . isdir ( " plugins/ " + plugin ) :
return redirect ( " /plugins " )
if not os . path . isfile ( " plugins/ " + plugin + " / " + plugin + " .json " ) :
return redirect ( " /plugins " )
with open ( " plugins/ " + plugin + " / " + plugin + " .json " ) as f :
data = json . load ( f )
data [ ' link ' ] = plugin
if ' name ' not in data :
data [ ' name ' ] = plugin
if ' description ' not in data :
data [ ' description ' ] = " No description provided "
if os . path . isfile ( " plugins/ " + plugin + " /main.py " ) :
# Get plugin/main.py listfunctions()
print ( " Loading plugin: " + plugin )
module = importlib . import_module ( " plugins. " + plugin + " .main " )
if function in module . listFunctions ( ) :
inputs = module . listFunctions ( ) [ function ] [ " params " ]
request_data = { }
for input in inputs :
2024-02-04 15:08:24 +11:00
request_data [ input ] = request . form . get ( input )
if inputs [ input ] [ ' type ' ] == " address " :
# Handle hip2
address_check = account_module . check_address ( request_data [ input ] , True , True )
if not address_check :
return redirect ( " /plugin/ " + plugin + " ?error=Invalid address " )
request_data [ input ] = address_check
elif inputs [ input ] [ ' type ' ] == " dns " :
# Handle URL encoding of DNS
request_data [ input ] = urllib . parse . unquote ( request_data [ input ] )
2024-02-02 21:40:02 +11:00
response = module . runFunction ( function , request_data , request . cookies . get ( " account " ) )
if not response :
return redirect ( " /plugin/ " + plugin + " ?error=An error occurred " )
if ' error ' in response :
return redirect ( " /plugin/ " + plugin + " ?error= " + response [ ' error ' ] )
response = render . plugin_output ( response , module . listFunctions ( ) [ function ] [ " returns " ] )
return render_template ( " plugin-output.html " , account = account , sync = account_module . getNodeSync ( ) ,
name = data [ ' name ' ] , description = data [ ' description ' ] , output = response )
else :
return jsonify ( { " error " : " Function not found " } )
return jsonify ( { " error " : " Plugin not found " } )
#endregion
2023-12-28 16:58:11 +11:00
#region Assets and default pages
@app.route ( ' /qr/<data> ' )
def qr ( data ) :
return send_file ( qrcode ( data , mode = " raw " ) , mimetype = " image/png " )
2024-02-01 23:41:22 +11:00
# Theme
@app.route ( ' /assets/css/styles.min.css ' )
def send_css ( ) :
print ( " Using theme: " + theme )
return send_from_directory ( ' themes ' , f ' { theme } .css ' )
2023-12-28 13:34:48 +11:00
@app.route ( ' /assets/<path:path> ' )
def send_assets ( path ) :
return send_from_directory ( ' templates/assets ' , path )
2023-12-28 16:04:45 +11:00
# Try path
@app.route ( ' /<path:path> ' )
def try_path ( path ) :
if os . path . isfile ( " templates/ " + path + " .html " ) :
return render_template ( path + " .html " )
else :
return page_not_found ( 404 )
2023-12-28 13:34:48 +11:00
@app.errorhandler ( 404 )
def page_not_found ( e ) :
account = account_module . check_account ( request . cookies . get ( " account " ) )
return render_template ( ' 404.html ' , account = account ) , 404
2023-12-28 16:58:11 +11:00
#endregion
2023-12-28 13:34:48 +11:00
if __name__ == ' __main__ ' :
2023-12-29 13:57:20 +11:00
app . run ( debug = True , host = ' 0.0.0.0 ' )