import json import random from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory,send_file import os import dotenv import requests import account as account_module import render import re from flask_qrcode import QRcode import domainLookup import urllib.parse import importlib import plugin as plugins_module dotenv.load_dotenv() app = Flask(__name__) qrcode = QRcode(app) # Change this if network fees change fees = 0.02 revokeCheck = random.randint(100000,999999) theme = os.getenv("theme") @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")) if not account: return redirect("/logout") 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) # 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) domain_count = len(domains) domainsMobile = render.domains(domains,True) domains = render.domains(domains) plugins = "" dashFunctions = plugins_module.getDashboardFunctions() for function in dashFunctions: functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{},account_module.check_account(request.cookies.get("account"))) plugins += render.plugin_output_dash(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"])) return render_template("index.html", account=account, available=available, total=total, pending=pending, domains=domains, domainsMobile=domainsMobile, plugins=plugins, 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) def reverseDirection(direction: str): if direction == "⬆": return "⬇" else: return "⬆" #region Transactions @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) return render_template("tx.html", account=account, sync=account_module.getNodeSync(), tx=transactions) @app.route('/send') def send_page(): # 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")) max = account_module.getBalance(account)['available'] # Subtract approx fee max = max - fees max = round(max, 2) message = '' address = '' amount = '' 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") return render_template("send.html", account=account,sync=account_module.getNodeSync(), max=max,message=message,address=address,amount=amount) @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") 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)) if amount > account_module.getBalance(account)['available'] - fees: return redirect("/send?message=Not enough funds to transfer&address=" + address + "&amount=" + str(amount)) toAddress = address if request.form.get('address') != address: toAddress = request.form.get('address') + "
" + address action = f"Send HNS to {request.form.get('address')}" content = f"Are you sure you want to send {amount} HNS to {toAddress}

" 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")) 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']) @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) return render_template("receive.html", account=account,sync=account_module.getNodeSync(), address=address) @app.route('/success') def success(): # 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") tx = request.args.get("tx") return render_template("success.html", account=account,sync=account_module.getNodeSync(), tx=tx) @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)}) #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() # Replace spaces with hyphens search_term = search_term.replace(" ","-") # Convert emoji to punycode search_term = domainLookup.emoji_to_punycode(search_term) if len(search_term) == 0: return redirect("/") domain = account_module.getDomain(search_term) plugins = "
" # Execute domain plugins searchFunctions = plugins_module.getSearchFunctions() for function in searchFunctions: functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":search_term},account_module.check_account(request.cookies.get("account"))) plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"])) plugins += "
" if 'error' in domain: return render_template("search.html", account=account,sync=account_module.getNodeSync(), search_term=search_term, domain=domain['error'],plugins=plugins) if domain['info'] is None: return render_template("search.html", account=account, sync=account_module.getNodeSync(), search_term=search_term,domain=search_term, state="AVAILABLE", next="Available Now",plugins=plugins) state = domain['info']['state'] if state == 'CLOSED': if domain['info']['registered']: state = 'REGISTERED' expires = domain['info']['stats']['daysUntilExpire'] next = f"Expires in ~{expires} days" else: state = 'AVAILABLE' next = "Available Now" elif state == "REVOKED": next = "Available Now" 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" 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) 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,plugins=plugins) @app.route('/manage/') def manage(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) domain_info = account_module.getDomain(domain) if 'error' in domain_info: return render_template("manage.html", account=account, sync=account_module.getNodeSync(), domain=domain, error=domain_info['error']) expiry = domain_info['info']['stats']['daysUntilExpire'] dns = account_module.getDNS(domain) raw_dns = str(dns).replace("'",'"') dns = render.dns(dns) 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" plugins = "
" # Execute domain plugins domainFunctions = plugins_module.getDomainFunctions() for function in domainFunctions: functionOutput = plugins_module.runPluginFunction(function["plugin"],function["function"],{"domain":domain},account_module.check_account(request.cookies.get("account"))) plugins += render.plugin_output(functionOutput,plugins_module.getPluginFunctionReturns(function["plugin"],function["function"])) plugins += "
" return render_template("manage.html", account=account, sync=account_module.getNodeSync(), error=errorMessage, address=address, domain=domain,expiry=expiry, dns=dns, raw_dns=urllib.parse.quote(raw_dns), finalize_time=finalize_time,plugins=plugins) @app.route('/manage//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) if response['error'] != None: print(response) return redirect("/manage/" + domain + "?error=" + response['error']['message']) return redirect("/success?tx=" + response['result']['hash']) @app.route('/manage//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//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}/?
" content += f"This will return the domain to the auction pool and you will lose any funds spent on the domain.
" content += f"This cannot be undone after the transaction is sent.

" 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//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: if response['error'] != None: print(response) return redirect("/manage/" + domain + "?error=" + response['error']['message']) return redirect("/success?tx=" + response['hash']) @app.route('/manage//renew') def renew(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() response = account_module.renewDomain(request.cookies.get("account"),domain) return redirect("/success?tx=" + response['hash']) @app.route('/manage//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//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']) @app.route('/manage//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') + "
" + address action = f"Send {domain}/ to {request.form.get('address')}" content = f"Are you sure you want to send {domain}/ to {toAddress}

" 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//sign') def signMessage(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 message = request.args.get("message") if message is None: return redirect("/manage/" + domain + "?error=Invalid message") content = "Message to sign:
" + message + "

" signedMessage = account_module.signMessage(request.cookies.get("account"),domain,message) if signedMessage["error"] != None: return redirect("/manage/" + domain + "?error=" + signedMessage["error"]) content += "Signature:
" + signedMessage["result"] + "

" data = { "domain": domain, "message": message, "signature": signedMessage["result"] } content += "Full information:
" + json.dumps(data,indent=4).replace('\n',"
") + "


" content += "" copyScript = "" content += "" + copyScript return render_template("message.html", account=account,sync=account_module.getNodeSync(), title="Sign Message",content=content) @app.route('/manage//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']) @app.route('/auction/') 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'Open Auction' 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'Rescan Auction' else: 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) if state == 'CLOSED': if not domainInfo['info']['registered']: state = 'AVAILABLE' next = "Available Now" next_action = f'Open Auction' 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'Manage' elif state == "REVOKED": next = "Available Now" next_action = f'Open Auction' 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'Reveal All' 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//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//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() bid = request.args.get("bid") blind = request.args.get("blind") if bid == "": bid = 0 if blind == "": blind = 0 bid = float(bid) blind = float(blind) if bid+blind == 0: return redirect("/auction/" + domain+ "?message=Invalid bid amount") # Show confirm page total = bid + blind action = f"Bid on {domain}/" content = f"Are you sure you want to bid on {domain}/?" content += "You are about to bid with the following details:

" content += f"Bid: {str(bid)} HNS
" content += f"Blind: {str(blind)} HNS
" content += f"Total: {total} HNS (excluding fees)

" 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//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() bid = request.args.get("bid") blind = request.args.get("blind") if bid == "": bid = 0 if blind == "": blind = 0 bid = float(bid) blind = float(blind) # Send the bid response = account_module.bid(request.cookies.get("account"),domain, float(bid), float(blind)) print(response) if 'error' in response: return redirect("/auction/" + domain + "?message=" + response['error']['message']) return redirect("/success?tx=" + response['hash']) @app.route('/auction//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) if 'error' in response: if response['error'] != None: return redirect("/auction/" + domain + "?message=" + response['error']['message']) print(response) return redirect("/success?tx=" + response['hash']) @app.route('/auction//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']) #endregion #region Settings @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/') 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 #region Account @app.route('/login') def login(): wallets = account_module.listWallets() wallets = render.wallets(wallets) if 'message' in request.args: return render_template("login.html", sync=account_module.getNodeSync(), error=request.args.get("message"),wallets=wallets) return render_template("login.html", sync=account_module.getNodeSync(), wallets=wallets) @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: return render_template("login.html", sync=account_module.getNodeSync(), error="Invalid account") account = account + ":" + password # Check if the account is valid if not account_module.check_account(account): return render_template("login.html", sync=account_module.getNodeSync(), error="Invalid account") # 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 @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

" + response['seed'])) response.set_cookie("account", account+":"+password) return response @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 @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)) #endregion #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") plugins = render.plugins(plugins_module.listPlugins()) return render_template("plugins.html", account=account, sync=account_module.getNodeSync(), plugins=plugins) @app.route('/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 plugins_module.pluginExists(plugin): return redirect("/plugins") data = plugins_module.getPluginData(plugin) functions = plugins_module.getPluginFunctions(plugin) 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'], author=data['author'],version=data['version'], functions=functions,error=error) @app.route('/plugin//', 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 plugins_module.pluginExists(plugin): return redirect("/plugins") data = plugins_module.getPluginData(plugin) # Get plugin/main.py listfunctions() if function in plugins_module.getPluginFunctions(plugin): inputs = plugins_module.getPluginFunctionInputs(plugin,function) request_data = {} for input in inputs: 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]) response = plugins_module.runPluginFunction(plugin,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,plugins_module.getPluginFunctionReturns(plugin,function)) 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"}) #endregion #region Assets and default pages @app.route('/qr/') def qr(data): return send_file(qrcode(data, mode="raw"), mimetype="image/png") # Theme @app.route('/assets/css/styles.min.css') def send_css(): print("Using theme: " + theme) return send_from_directory('themes', f'{theme}.css') @app.route('/assets/') def send_assets(path): return send_from_directory('templates/assets', path) # Try path @app.route('/') def try_path(path): if os.path.isfile("templates/" + path + ".html"): return render_template(path + ".html") else: return page_not_found(404) @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 #endregion if __name__ == '__main__': app.run(debug=True,host='0.0.0.0')