From d483cfdcfda867a3447aba8047bfb5ec8cf11780 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 14:49:14 +1000 Subject: [PATCH 1/9] feat: Add testing CI workflow --- .gitea/workflows/test.yml | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .gitea/workflows/test.yml diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..313ed84 --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,40 @@ +name: Test Python Compatibility +run-name: Test Python Compatibility +on: + push: + +jobs: + Python-Compatibility: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] + fail-fast: false + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then + pip install -r requirements.txt + fi + pip install pytest + + - name: Run tests + run: | + echo "Testing with Python ${{ matrix.python-version }}" + python -m pytest main.py + + - name: Check compatibility + run: | + # Add any additional compatibility checks if needed + python --version + python -c "import sys; print(f'Python {sys.version_info.major}.{sys.version_info.minor} compatibility test passed')" \ No newline at end of file -- 2.49.1 From 06b1eea9ef2e15dbaeb0563565ad074ab590b62b Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 14:55:40 +1000 Subject: [PATCH 2/9] fix: Disable arm on testing workflow --- .gitea/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 313ed84..49ff827 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -5,7 +5,7 @@ on: jobs: Python-Compatibility: - runs-on: ubuntu-latest + runs-on: [ubuntu-latest, amd] strategy: matrix: python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] -- 2.49.1 From 2d51882d20fb37f8d5fcd1645951069a56623d62 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:00:40 +1000 Subject: [PATCH 3/9] fix: Specify python minor version number --- .gitea/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 49ff827..f023abe 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -8,7 +8,7 @@ jobs: runs-on: [ubuntu-latest, amd] strategy: matrix: - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] + python-version: ['3.6.15', '3.7.17', '3.8.18', '3.9.23', '3.10.18', '3.13.7'] fail-fast: false steps: -- 2.49.1 From e0f24267f575c211d9b6815e34f781a5549e6d8a Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:10:23 +1000 Subject: [PATCH 4/9] test: Try a new container to run --- .gitea/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index f023abe..ca14316 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -6,9 +6,10 @@ on: jobs: Python-Compatibility: runs-on: [ubuntu-latest, amd] + container: catthehacker/ubuntu:act-latest strategy: matrix: - python-version: ['3.6.15', '3.7.17', '3.8.18', '3.9.23', '3.10.18', '3.13.7'] + python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.13'] fail-fast: false steps: -- 2.49.1 From 56eabfc1fc8d1036a9e553428eaba1a6a8651983 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:20:31 +1000 Subject: [PATCH 5/9] feat: Add some inital tests --- .gitea/workflows/test.yml | 8 +------- main.py | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ca14316..4dbf70b 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -32,10 +32,4 @@ jobs: - name: Run tests run: | echo "Testing with Python ${{ matrix.python-version }}" - python -m pytest main.py - - - name: Check compatibility - run: | - # Add any additional compatibility checks if needed - python --version - python -c "import sys; print(f'Python {sys.version_info.major}.{sys.version_info.minor} compatibility test passed')" \ No newline at end of file + python -m pytest main.py \ No newline at end of file diff --git a/main.py b/main.py index e374506..299d20c 100644 --- a/main.py +++ b/main.py @@ -1906,3 +1906,9 @@ if __name__ == '__main__': app.run(debug=True) else: app.run() + +def tests(): + assert blocks_to_time(6) == "1 hrs" + assert blocks_to_time(3) == "30 mins" + assert blocks_to_time(1) == "10 mins" + assert blocks_to_time(10) == "1 hrs 40 mins" \ No newline at end of file -- 2.49.1 From 30de2d585ec59686e1d066b5ccf1b34dfaea24fd Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:28:39 +1000 Subject: [PATCH 6/9] fix: Use single quote in sign message and reduce test versions --- .gitea/workflows/test.yml | 2 +- account.py | 1 - main.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 4dbf70b..a4f4c92 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,7 +9,7 @@ jobs: container: catthehacker/ubuntu:act-latest strategy: matrix: - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.13'] + python-version: ['3.8', '3.10', '3.13'] fail-fast: false steps: diff --git a/account.py b/account.py index 4ba99bd..10a370d 100644 --- a/account.py +++ b/account.py @@ -13,7 +13,6 @@ import signal import sys import threading import sqlite3 -from functools import wraps dotenv.load_dotenv() diff --git a/main.py b/main.py index 299d20c..55f78bd 100644 --- a/main.py +++ b/main.py @@ -849,7 +849,7 @@ def signMessage(domain): signedMessage = account_module.signMessage(request.cookies.get("account"),domain,message) if signedMessage["error"] != None: return redirect("/manage/" + domain + "?error=" + signedMessage["error"]) - content += f"Signature:
{signedMessage["result"]}

" + content += f"Signature:
{signedMessage['result']}

" data = { "domain": domain, -- 2.49.1 From 997828795abdf6f00e6aa06b0ceca37ac46c58c8 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:48:21 +1000 Subject: [PATCH 7/9] feat: Add ruff linting --- .gitea/workflows/test.yml | 13 ++++--- account.py | 71 ++++++++++++++++++++------------------- domainLookup.py | 5 ++- main.py | 32 +++++++++--------- plugins/automations.py | 1 - plugins/batching.py | 2 -- plugins/customPlugins.py | 2 -- plugins/renewal.py | 2 -- render.py | 46 ++++++++++++------------- server.py | 5 ++- 10 files changed, 86 insertions(+), 93 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a4f4c92..40fe5ac 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,14 +9,14 @@ jobs: container: catthehacker/ubuntu:act-latest strategy: matrix: - python-version: ['3.8', '3.10', '3.13'] + python-version: ['3.10', '3.11', '3.13'] fail-fast: false steps: - name: Checkout uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -27,9 +27,14 @@ jobs: if [ -f requirements.txt ]; then pip install -r requirements.txt fi - pip install pytest + pip install pytest ruff - name: Run tests run: | echo "Testing with Python ${{ matrix.python-version }}" - python -m pytest main.py \ No newline at end of file + python -m pytest main.py + + - name: Lint with ruff + run: | + echo "Linting with Python ${{ matrix.python-version }}" + ruff check \ No newline at end of file diff --git a/account.py b/account.py index 10a370d..ed41e18 100644 --- a/account.py +++ b/account.py @@ -130,7 +130,7 @@ def check_password(cookie: str|None, password: str|None): password = "" account = check_account(cookie) - if account == False: + if not account: return False # Check if the password is valid @@ -638,7 +638,7 @@ def check_address(address: str, allow_name: bool = True, return_address: bool = return False return 'Invalid address' - if response['result']['isvalid'] == True: + if response['result']['isvalid']: if return_address: return address return 'Valid address' @@ -788,7 +788,7 @@ def getAddressFromCoin(coinhash: str, coinindex = 0): # Get the address from the hash response = requests.get(get_node_api_url(f"coin/{coinhash}/{coinindex}")) if response.status_code != 200: - print(f"Error getting address from coin") + print("Error getting address from coin") return "No Owner" data = response.json() if 'address' not in data: @@ -801,7 +801,7 @@ def renewDomain(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -834,7 +834,7 @@ def getDNS(domain: str): return { "error": "No DNS records" } - if response['result'] == None: + if response['result'] is None: return [] if 'records' not in response['result']: @@ -846,7 +846,7 @@ def setDNS(account, domain, records): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -918,7 +918,7 @@ def getNodeSync(): def getWalletStatus(): response = hsw.rpc_getWalletInfo() - if 'error' in response and response['error'] != None: + if 'error' in response and response['error'] is not None: return "Error" # return response @@ -967,7 +967,7 @@ def getPendingReveals(account): if bid['name'] == domain['name']: state_found = False for reveal in reveals: - if reveal['own'] == True: + if reveal['own']: if bid['value'] == reveal['value']: state_found = True @@ -997,8 +997,8 @@ def getPendingRedeems(account, password): pending.append(nameHash) else: pending.append(name['result']) - except: - print("Failed to parse redeems") + except Exception as e: + print(f"Failed to parse redeems: {str(e)}") return pending @@ -1008,7 +1008,7 @@ def getPendingRegisters(account): domains = getDomains(account, False) pending = [] for domain in domains: - if domain['state'] == "CLOSED" and domain['registered'] == False: + if domain['state'] == "CLOSED" and not domain['registered']: for bid in bids: if bid['name'] == domain['name']: if bid['value'] == domain['highest']: @@ -1026,9 +1026,9 @@ def getPendingFinalizes(account, password): pending = [] try: for output in tx['outputs']: - if type(output) != dict: + if type(output) is not dict: continue - if not 'covenant' in output: + if 'covenant' not in output: continue if output['covenant'].get("type") != 10: continue @@ -1041,8 +1041,8 @@ def getPendingFinalizes(account, password): pending.append(nameHash) else: pending.append(name['result']) - except: - print("Failed to parse finalizes") + except Exception as e: + print(f"Failed to parse finalizes: {str(e)}") return pending @@ -1065,7 +1065,7 @@ def revealAuction(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1085,7 +1085,7 @@ def revealAll(account): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1119,7 +1119,7 @@ def redeemAll(account): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1151,9 +1151,8 @@ def redeemAll(account): def registerAll(account): account_name = check_account(account) - password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1176,9 +1175,8 @@ def registerAll(account): def finalizeAll(account): account_name = check_account(account) - password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1211,7 +1209,7 @@ def bid(account, domain, bid, blind): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1236,7 +1234,7 @@ def openAuction(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1258,7 +1256,7 @@ def transfer(account, domain, address): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1280,7 +1278,7 @@ def finalize(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1317,7 +1315,7 @@ def cancelTransfer(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1354,7 +1352,7 @@ def revoke(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1391,7 +1389,7 @@ def sendBatch(account, batch): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1440,7 +1438,7 @@ def createBatch(account, batch): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1589,7 +1587,7 @@ def zapTXs(account): account_name = check_account(account) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1615,7 +1613,7 @@ def getxPub(account): if account.count(":") > 0: account_name = check_account(account) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1643,7 +1641,7 @@ def signMessage(account, domain, message): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1683,6 +1681,7 @@ def verifyMessageWithName(domain, signature, message): return response['result'] return False except Exception as e: + print(f"Error verifying message with name: {str(e)}") return False @@ -1693,6 +1692,7 @@ def verifyMessage(address, signature, message): return response['result'] return False except Exception as e: + print(f"Error verifying message: {str(e)}") return False # endregion @@ -1739,7 +1739,7 @@ def get_node_api_url(path=''): base_url = f"http://x:{HSD_API}@{HSD_IP}:{HSD_NODE_PORT}" if isSPV() and any(path.startswith(route) for route in SPV_EXTERNAL_ROUTES): # If in SPV mode and the path is one of the external routes, use the external API - base_url = f"https://hsd.hns.au/api/v1" + base_url = "https://hsd.hns.au/api/v1" if path: # Ensure path starts with a slash if it's not empty @@ -1945,7 +1945,8 @@ def hsdStart(): try: signal.signal(signal.SIGINT, lambda s, f: (hsdStop(), sys.exit(0))) signal.signal(signal.SIGTERM, lambda s, f: (hsdStop(), sys.exit(0))) - except: + except Exception as e: + print(f"Failed to set signal handlers: {str(e)}") pass diff --git a/domainLookup.py b/domainLookup.py index 353a61e..ad0ab3c 100644 --- a/domainLookup.py +++ b/domainLookup.py @@ -11,7 +11,6 @@ import dns.query import dns.rdatatype import httpx from requests_doh import DNSOverHTTPSSession, add_dns_provider -import requests import urllib3 from cryptography.x509.oid import ExtensionOID @@ -172,11 +171,11 @@ def resolve_TLSA_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"): def emoji_to_punycode(emoji): try: return emoji.encode("idna").decode("ascii") - except Exception as e: + except Exception: return emoji def punycode_to_emoji(punycode): try: return punycode.encode("ascii").decode("idna") - except Exception as e: + except Exception: return punycode \ No newline at end of file diff --git a/main.py b/main.py index 55f78bd..6c77bfa 100644 --- a/main.py +++ b/main.py @@ -12,11 +12,9 @@ import re from flask_qrcode import QRcode import domainLookup import urllib.parse -import importlib import plugin as plugins_module import gitinfo import datetime -import functools import time dotenv.load_dotenv() @@ -196,7 +194,7 @@ def send(): 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" + cancel = "/send" confirm = f"/send/confirm?address={address}&amount={amount}" @@ -645,9 +643,9 @@ def revokeInit(domain: str): 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." + content += "This will return the domain to the auction pool and you will lose any funds spent on the domain.
" + content += "This cannot be undone after the transaction is sent.

" + content += "Please enter your password to confirm." cancel = f"/manage/{domain}" confirm = f"/manage/{domain}/revoke/confirm" @@ -820,7 +818,7 @@ def transfer(domain): 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." + content += "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}" @@ -918,7 +916,7 @@ def auction(domain): if domainInfo['info'] is None: if 'registered' in domainInfo and domainInfo['registered'] == False and 'expired' in domainInfo and domainInfo['expired'] == False: # Needs to be registered - next_action = f'ERROR GETTING NEXT STATE' + next_action = 'ERROR GETTING NEXT STATE' else: next_action = f'Open Auction' return render_template("auction.html", account=account, @@ -965,7 +963,7 @@ def auction(domain): elif stats['blocksUntilReveal'] == 2: next += "
LAST CHANCE TO BID" elif stats['blocksUntilReveal'] == 3: - next += f"
Next block is last chance to bid" + next += "
Next block is last chance to bid" elif stats['blocksUntilReveal'] < 6: next += f"
Last chance to bid in {stats['blocksUntilReveal']-2} blocks" @@ -1229,7 +1227,7 @@ def settings_action(action): @app.route('/settings/upload', methods=['POST']) def upload_image(): - if not 'account' in request.cookies: + if 'account' not in request.cookies: return redirect("/login?message=Not logged in") account = request.cookies.get("account") @@ -1253,7 +1251,7 @@ def upload_image(): return redirect("/settings?error=An error occurred") def latestVersion(branch): - result = requests.get(f"https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches") + result = requests.get("https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches") if result.status_code != 200: return "Error" @@ -1628,7 +1626,7 @@ def api_hsd(function): elif stats['blocksUntilReveal'] == 2: next += "
LAST CHANCE TO BID" elif stats['blocksUntilReveal'] == 3: - next += f"
Next block is last chance to bid" + next += "
Next block is last chance to bid" elif stats['blocksUntilReveal'] < 6: next += f"
Last chance to bid in {stats['blocksUntilReveal']-2} blocks" @@ -1783,9 +1781,9 @@ def api_wallet(function): if function == "icon": # Check if there is an icon - if not os.path.exists(f'user_data/images'): + if not os.path.exists('user_data/images'): return send_file('templates/assets/img/HNS.png') - files = os.listdir(f'user_data/images') + files = os.listdir('user_data/images') for file in files: if file.startswith(account): return send_file(f'user_data/images/{file}') @@ -1820,9 +1818,9 @@ def api_wallet_mobile(function): @app.route('/api/v1/icon/') def api_icon(account): - if not os.path.exists(f'user_data/images'): + if not os.path.exists('user_data/images'): return send_file('templates/assets/img/HNS.png') - files = os.listdir(f'user_data/images') + files = os.listdir('user_data/images') for file in files: if file.startswith(account): return send_file(f'user_data/images/{file}') @@ -1854,7 +1852,7 @@ def renderDomain(name: str) -> str: return f"{rendered}/ ({name})" - except Exception as e: + except Exception: return f"{name}/" #endregion diff --git a/plugins/automations.py b/plugins/automations.py index b062015..3452f21 100644 --- a/plugins/automations.py +++ b/plugins/automations.py @@ -1,4 +1,3 @@ -import json import account import requests import threading diff --git a/plugins/batching.py b/plugins/batching.py index 9dc6663..17d97ac 100644 --- a/plugins/batching.py +++ b/plugins/batching.py @@ -1,7 +1,5 @@ -import json import account import requests -import os diff --git a/plugins/customPlugins.py b/plugins/customPlugins.py index 0f2a09c..65308a7 100644 --- a/plugins/customPlugins.py +++ b/plugins/customPlugins.py @@ -1,6 +1,4 @@ import json -import account -import requests import os # Plugin Data diff --git a/plugins/renewal.py b/plugins/renewal.py index 9819e8b..2adc2b0 100644 --- a/plugins/renewal.py +++ b/plugins/renewal.py @@ -1,7 +1,5 @@ -import json import account import requests -import os # Plugin Data info = { diff --git a/render.py b/render.py index e48ec3f..a9fea93 100644 --- a/render.py +++ b/render.py @@ -2,9 +2,7 @@ import datetime import json import urllib.parse from flask import render_template -from domainLookup import punycode_to_emoji import os -from handywrapper import api import threading import requests @@ -182,7 +180,7 @@ def transactions(txs): elif amount > 0: amount = f"+{amount:,.2f}" else: - amount = f"0.00" + amount = "0.00" # hash = f"{hash[:8]}..." @@ -261,7 +259,7 @@ def txs(data): html_output += f"{amount:,.2f} + {blind:,.2f} HNS\n" html_output += f"{timestamp_to_readable_time(entry['time'])}\n" - html_output += f"\n" + html_output += "\n" return html_output @@ -316,13 +314,13 @@ def bids(bids,reveals): html += f"{value:,.2f} HNS" html += f"{bidValue:,.2f} HNS" else: - html += f"Hidden until reveal" - html += f"Hidden until reveal" + html += "Hidden until reveal" + html += "Hidden until reveal" if bid['own']: html += "You" else: - html += f"Unknown" + html += "Unknown" html += f"Bid TX 🔗" html += "" @@ -410,22 +408,22 @@ def plugin_functions(functions, pluginName): functionType = functions[function]["type"] - html += f'
' - html += f'
' + html += '
' + html += '
' html += f'

{name}

' html += f'
{description}
' html += f'
Function type: {functionType.capitalize()}
' if functionType != "default": html += f'

Returns: {returns}

' - html += f'
' - html += f'
' + html += '
' + html += '
' continue # Form html += f'
' for param in params: - html += f'
' + html += '
' paramName = params[param]["name"] paramType = params[param]["type"] if paramType == "text": @@ -449,14 +447,14 @@ def plugin_functions(functions, pluginName): - html += f'
' + html += '
' - html += f'' - html += f'
' + html += '' + html += '' # For debugging html += f'

Returns: {returns}

' - html += f'' - html += f'' + html += '' + html += '' return html @@ -468,16 +466,16 @@ def plugin_output(outputs, returns): for returnOutput in returns: if returnOutput not in outputs: continue - html += f'
' - html += f'
' + html += '
' + html += '
' html += f'

{returns[returnOutput]["name"]}

' output = outputs[returnOutput] if returns[returnOutput]["type"] == "list": - html += f'
    ' + html += '
      ' for item in output: html += f'
    • {item}
    • ' - html += f'
    ' + html += '
' elif returns[returnOutput]["type"] == "text": html += f'

{output}

' elif returns[returnOutput]["type"] == "tx": @@ -487,8 +485,8 @@ def plugin_output(outputs, returns): html += render_template('components/dns-output.html', dns=dns(output)) - html += f'
' - html += f'
' + html += '
' + html += '
' return html def plugin_output_dash(outputs, returns): @@ -517,7 +515,7 @@ def renderDomain(name: str) -> str: return f"{rendered}/ ({name})" - except Exception as e: + except Exception: return f"{name}/" def renderDomainAsync(namehash: str) -> None: diff --git a/server.py b/server.py index f8e1153..53d6e12 100644 --- a/server.py +++ b/server.py @@ -1,4 +1,3 @@ -import os import sys import platform from main import app @@ -39,6 +38,6 @@ if __name__ == '__main__': sys.exit() print(f'Starting server with Waitress on {platform.system()} with {threads} threads...', flush=True) - print(f'Press Ctrl+C to stop the server', flush=True) - print(f'Serving on http://0.0.0.0:5000/', flush=True) + print('Press Ctrl+C to stop the server', flush=True) + print('Serving on http://0.0.0.0:5000/', flush=True) serve(app, host="0.0.0.0", port=5000, threads=threads) -- 2.49.1 From e7b787c30baf209fdc25ce4f470d1da1193e602b Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:55:45 +1000 Subject: [PATCH 8/9] fix: Lint to follow ruff standards --- main.py | 72 +++++++++++++++++++++++++++---------------------------- plugin.py | 12 ++++++---- render.py | 6 ++--- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/main.py b/main.py index 6c77bfa..aa5fc9b 100644 --- a/main.py +++ b/main.py @@ -112,7 +112,7 @@ def transactions(): page = request.args.get('page', 1) try: page = int(page) - except: + except ValueError: page = 1 if page < 1: @@ -209,7 +209,7 @@ def sendConfirmed(): address = request.args.get("address") amount = float(request.args.get("amount","0")) 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'] is not None: # If error is a dict get the message if isinstance(response['error'], dict): if 'message' in response['error']: @@ -280,7 +280,7 @@ def auctions(): # Sort sort = request.args.get("sort") - if sort == None: + if sort is None: sort = "time" sort = sort.lower() sort_price = "" @@ -294,7 +294,7 @@ def auctions(): reverse = False direction = request.args.get("direction") - if direction == None: + if direction is None: if sort == "time": direction = "⬆" else: @@ -363,7 +363,7 @@ def revealAllBids(): return redirect("/auctions?message=Failed to reveal bids") if 'error' in response: - if response['error'] != None: + if response['error'] is not None: if response['error']['message'] == "Nothing to do.": return redirect("/auctions?message=No reveals pending") return redirect("/auctions?message=" + response['error']['message']) @@ -386,7 +386,7 @@ def redeemAllBids(): return redirect("/auctions?message=Failed to redeem bids") if 'error' in response: - if response['error'] != None: + if response['error'] is not None: if response['error']['message'] == "Nothing to do.": return redirect("/auctions?message=No redeems pending") return redirect("/auctions?message=" + response['error']['message']) @@ -408,7 +408,7 @@ def registerAllDomains(): return redirect("/auctions?message=Failed to register domains") if 'error' in response: - if response['error'] != None: + if response['error'] is not None: if response['error']['message'] == "Nothing to do.": return redirect("/auctions?message=No domains to register") return redirect("/auctions?message=" + response['error']['message']) @@ -427,7 +427,7 @@ def finalizeAllBids(): response = account_module.finalizeAll(request.cookies.get("account")) if 'error' in response: - if response['error'] != None: + if response['error'] is not None: if response['error']['message'] == "Nothing to do.": return redirect("/dashboard?message=No domains to finalize") return redirect("/dashboard?message=" + response['error']['message']) @@ -505,7 +505,6 @@ def search(): domain_info = account_module.getDomain(search_term) owner = 'Unknown' dns = [] - txs = [] if domain_info: # Check if info and info.owner @@ -558,10 +557,10 @@ def manage(domain: str): dns = render.dns(dns) errorMessage = request.args.get("error") - if errorMessage == None: + if errorMessage is None: errorMessage = "" address = request.args.get("address") - if address == None: + if address is None: address = "" finalize_time = "" @@ -605,7 +604,7 @@ def finalize(domain: str): domain = domain.lower() response = account_module.finalize(request.cookies.get("account"),domain) - if response['error'] != None: + if response['error'] is not None: print(response) return redirect("/manage/" + domain + "?error=" + response['error']['message']) @@ -624,7 +623,7 @@ def cancelTransfer(domain: str): domain = domain.lower() response = account_module.cancelTransfer(request.cookies.get("account"),domain) if 'error' in response: - if response['error'] != None: + if response['error'] is not None: print(response) return redirect("/manage/" + domain + "?error=" + response['error']['message']) @@ -674,13 +673,13 @@ def revokeConfirm(domain: str): return redirect("/manage/" + domain + "?error=An error occurred. Please try again.") response = account_module.check_password(request.cookies.get("account"),password) - if response == False: + if not response: return redirect("/manage/" + domain + "?error=Invalid password") response = account_module.revoke(request.cookies.get("account"),domain) if 'error' in response: - if response['error'] != None: + if response['error'] is not None: print(response) return redirect("/manage/" + domain + "?error=" + response['error']['message']) @@ -720,7 +719,7 @@ def editPage(domain: str): user_edits = request.args.get("dns") - if user_edits != None: + if user_edits is not None: dns = urllib.parse.unquote(user_edits) else: dns = account_module.getDNS(domain) @@ -733,7 +732,7 @@ def editPage(domain: str): # 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 is not None and dnsValue is not None: if dnsType != "DS": dns.append({"type": dnsType, "value": dnsValue}) else: @@ -747,7 +746,7 @@ def editPage(domain: str): key_tag = int(ds[0]) algorithm = int(ds[1]) digest_type = int(ds[2]) - except: + except ValueError: raw_dns = str(dns).replace("'",'"') return redirect("/manage/" + domain + "/edit?dns=" + urllib.parse.quote(str(raw_dns)) + "&error=Invalid DS record") @@ -759,7 +758,7 @@ def editPage(domain: str): raw_dns = str(dns).replace("'",'"') dns = render.dns(dns,True) errorMessage = request.args.get("error") - if errorMessage == None: + if errorMessage is None: errorMessage = "" @@ -845,7 +844,7 @@ def signMessage(domain): content = "Message to sign:
" + message + "

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

" @@ -904,7 +903,7 @@ def auction(domain): domainInfo = account_module.getDomain(search_term) error = request.args.get("error") - if error == None: + if error is None: error = "" if 'error' in domainInfo: @@ -914,7 +913,7 @@ def auction(domain): error=error) if domainInfo['info'] is None: - if 'registered' in domainInfo and domainInfo['registered'] == False and 'expired' in domainInfo and domainInfo['expired'] == False: + if 'registered' in domainInfo and not domainInfo['registered'] and 'expired' in domainInfo and not domainInfo['expired']: # Needs to be registered next_action = 'ERROR GETTING NEXT STATE' else: @@ -995,7 +994,7 @@ def rescan_auction(domain): domain = domain.lower() - response = account_module.rescan_auction(account,domain) + account_module.rescan_auction(account,domain) return redirect("/auction/" + domain) @app.route('/auction//bid') @@ -1091,7 +1090,7 @@ def open_auction(domain): response = account_module.openAuction(request.cookies.get("account"),domain) if 'error' in response: - if response['error'] != None: + if response['error'] is not None: return redirect("/auction/" + domain + "?error=" + response['error']['message']) return redirect(f"/success?tx={response['hash']}") @@ -1140,10 +1139,10 @@ def settings(): return redirect("/logout") error = request.args.get("error") - if error == None: + if error is None: error = "" success = request.args.get("success") - if success == None: + if success is None: success = "" @@ -1202,7 +1201,7 @@ def settings_action(action): if action == "zap": resp = account_module.zapTXs(request.cookies.get("account")) - if type(resp) == dict and 'error' in resp: + if type(resp) is dict and 'error' in resp: return redirect("/settings?error=" + str(resp['error'])) return redirect("/settings?success=Zapped transactions") @@ -1288,7 +1287,7 @@ def login_post(): account = request.form.get("account") password = request.form.get("password") - if account == None or password == None: + if account is None or password is None: wallets = account_module.listWallets() wallets = render.wallets(wallets) return render_template("login.html", @@ -1327,7 +1326,7 @@ def register(): password = request.form.get("password") repeatPassword = request.form.get("password_repeat") - if account == None or password == None or repeatPassword == None: + if account is None or password is None or repeatPassword is None: return render_template("register.html", error="Invalid account or password", name=account,password=password,password_repeat=repeatPassword) @@ -1374,7 +1373,7 @@ def import_wallet(): repeatPassword = request.form.get("password_repeat") seed = request.form.get("seed") - if account == None or password == None or repeatPassword == None or seed == None: + if account is None or password is None or repeatPassword is None or seed is None: return render_template("import-wallet.html", error="Invalid account, password or seed", name=account,password=password,password_repeat=repeatPassword, @@ -1473,12 +1472,12 @@ def plugin(ptype,plugin): functions = plugins_module.getPluginFunctions(plugin) functions = render.plugin_functions(functions,plugin) - if data['verified'] == False: + if not data['verified']: functions = "
" + functions error = request.args.get("error") - if error == None: + if error is None: error = "" return render_template("plugin.html", account=account, @@ -1504,7 +1503,7 @@ def plugin_verify(ptype,plugin): data = plugins_module.getPluginData(plugin) - if data['verified'] == False: + if not data['verified']: plugins_module.verifyPlugin(plugin) return redirect("/plugin/" + plugin) @@ -1591,7 +1590,7 @@ def api_hsd(function): if not domain: return jsonify({"error": "No domain specified"}), 400 domainInfo = account_module.getDomain(domain) - if 'error' in domainInfo and domainInfo['error'] != None: + if 'error' in domainInfo and domainInfo['error'] is not None: return jsonify({"error": domainInfo['error']}), 400 stats = domainInfo['info']['stats'] if 'stats' in domainInfo['info'] else {} state = domainInfo['info']['state'] @@ -1712,7 +1711,7 @@ def api_wallet(function): if function == "domains": domains = account_module.getDomains(account) - if type(domains) == dict and 'error' in domains: + if type(domains) is dict and 'error' in domains: return jsonify({"result": [], "error": domains['error']}) # Add nameRender to each domain @@ -1726,7 +1725,7 @@ def api_wallet(function): page = request.args.get('page', 1) try: page = int(page) - except: + except ValueError: page = 1 if page < 1: @@ -1799,7 +1798,6 @@ def api_wallet_mobile(function): return jsonify({"error": "Not logged in"}) account = account_module.check_account(request.cookies.get("account")) - password = request.cookies.get("account","").split(":")[1] if not account: return jsonify({"error": "Invalid account"}) diff --git a/plugin.py b/plugin.py index ec4b923..4695b87 100644 --- a/plugin.py +++ b/plugin.py @@ -62,7 +62,8 @@ def listPlugins(update=False): try: with open("user_data/plugin_signatures.json", "r") as f: signatures = json.load(f) - except: + except Exception as e: + print(f"Error loading plugin signatures: {e}") # Write a new signatures file with open("user_data/plugin_signatures.json", "w") as f: json.dump(signatures, f) @@ -87,7 +88,8 @@ def verifyPlugin(plugin: str): try: with open("user_data/plugin_signatures.json", "r") as f: signatures = json.load(f) - except: + except Exception as e: + print(f"Error loading plugin signatures: {e}") # Write a new signatures file with open("user_data/plugin_signatures.json", "w") as f: json.dump(signatures, f) @@ -120,7 +122,8 @@ def getPluginData(pluginStr: str): try: with open("user_data/plugin_signatures.json", "r") as f: signatures = json.load(f) - except: + except Exception as e: + print(f"Error loading plugin signatures: {e}") # Write a new signatures file with open("user_data/plugin_signatures.json", "w") as f: json.dump(signatures, f) @@ -171,7 +174,8 @@ def runPluginFunction(plugin: str, function: str, params: dict, authentication: try: with open("user_data/plugin_signatures.json", "r") as f: signatures = json.load(f) - except: + except Exception as e: + print(f"Error loading plugin signatures: {e}") # Write a new signatures file with open("user_data/plugin_signatures.json", "w") as f: json.dump(signatures, f) diff --git a/render.py b/render.py index a9fea93..626ea74 100644 --- a/render.py +++ b/render.py @@ -53,7 +53,7 @@ def domains(domains, mobile=False): link = f'/manage/{domain["name"]}' link_action = "Manage" - if domain['registered'] == False: + if not domain['registered']: link_action = "Register" link = f'/auction/{domain["name"]}/register' @@ -251,7 +251,7 @@ def txs(data): amount = entry['amount'] amount = amount / 1000000 - if entry['blind'] == None: + if entry['blind'] is None: html_output += f"{amount:,.2f} HNS\n" else: blind = entry['blind'] @@ -496,7 +496,7 @@ def plugin_output_dash(outputs, returns): for returnOutput in returns: if returnOutput not in outputs: continue - if outputs[returnOutput] == None: + if outputs[returnOutput] is None: continue html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output=outputs[returnOutput]) return html -- 2.49.1 From 86e174c337768ed1bbf20d63a7b646bab0f2c665 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:58:55 +1000 Subject: [PATCH 9/9] fix: Lint default plugins --- plugins/automations.py | 2 +- plugins/batching.py | 2 +- plugins/renewal.py | 2 +- plugins/varo.py | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/automations.py b/plugins/automations.py index 3452f21..d54794c 100644 --- a/plugins/automations.py +++ b/plugins/automations.py @@ -126,7 +126,7 @@ def automations_background(authentication): account_name = account.check_account(authentication) password = ":".join(authentication.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" diff --git a/plugins/batching.py b/plugins/batching.py index 17d97ac..9fe63c1 100644 --- a/plugins/batching.py +++ b/plugins/batching.py @@ -382,7 +382,7 @@ def bid(params, authentication): bid = float(params["bid"]) blind = float(params["blind"]) blind+=bid - except: + except ValueError: return { "status":"Invalid bid amount", "transaction":None diff --git a/plugins/renewal.py b/plugins/renewal.py index 2adc2b0..0956e81 100644 --- a/plugins/renewal.py +++ b/plugins/renewal.py @@ -88,7 +88,7 @@ def main(params, authentication): return {"status": f"Failed: {batch['error']['message']}", "transaction": "None"} if 'result' in batch: - if batch['result'] != None: + if batch['result'] is not None: tx = batch['result']['hash'] return {"status": "Success", "transaction": tx} # Note only one batch can be sent at a time diff --git a/plugins/varo.py b/plugins/varo.py index 4247e46..16d380b 100644 --- a/plugins/varo.py +++ b/plugins/varo.py @@ -93,7 +93,7 @@ def status(params, authentication): response = requests.post(f"https://{instance}/api", json=data, headers=headers) if response.status_code != 200: return {"status": "Error connecting to Varo"} - if response.json()["success"] != True: + if not response.json()["success"]: return {"status": "Error connecting to Varo"} return {"status": f"Connected to {instance}"} @@ -110,7 +110,7 @@ def login(params, authentication): if response.status_code != 200: return {"status": "Error connecting to Varo"} - if response.json()["success"] != True: + if not response.json()["success"]: return {"status": "Error connecting to Varo"} auth = { @@ -146,7 +146,7 @@ def addDomain(params, authentication): zones = requests.post(f"https://{instance}/api", json=data, headers=headers) if zones.status_code != 200: return {"status": "Error connecting to Varo"} - if zones.json()["success"] != True: + if not zones.json()["success"]: return {"status": "Error connecting to Varo"} zones = zones.json()["data"] @@ -169,7 +169,7 @@ def addDomain(params, authentication): response = requests.post(f"https://{instance}/api", json=data, headers=headers) if response.status_code != 200: return {"status": "Error connecting to Varo"} - if response.json()["success"] != True: + if not response.json()["success"]: return {"status": "Error connecting to Varo"} zoneID = response.json()["data"]["zone"] data = { @@ -179,7 +179,7 @@ def addDomain(params, authentication): response = requests.post(f"https://{instance}/api", json=data, headers=headers) if response.status_code != 200: return {"status": "Error connecting to Varo"} - if response.json()["success"] != True: + if not response.json()["success"]: return {"status": "Error connecting to Varo"} zone = response.json()["data"] -- 2.49.1