From 359477456802840dc15ed0a3f8f7c5bdef42afcf Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Sat, 14 Sep 2024 17:29:19 +1000 Subject: [PATCH] feat: Add renewal script --- .env.example | 5 ++ .gitignore | 3 ++ README.md | 48 ++++++++++++++++- renew.py | 135 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 renew.py create mode 100644 requirements.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0c38c08 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +API_KEY=hsd-api-key +ACCOUNT=wallet-name +PASSWORD=wallet-password +RENEW_TYPE=expiring +RENEW_DAYS=365 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31cdf2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +node_modules/ +hsd-ledger/ \ No newline at end of file diff --git a/README.md b/README.md index 5965106..29f9cc5 100644 --- a/README.md +++ b/README.md @@ -1 +1,47 @@ -# renew-all +# Renew All Domains in Bob or HSD + +Make sure you have these installed: +- Node.js and npm (https://nodejs.org/en/download/) +- Git (https://git-scm.com/downloads) +- Python3 + + +Install hsd-ledger package: +```bash +git clone https://github.com/Nathanwoodburn/hsd-ledger.git +cd hsd-ledger +npm install +``` + +Make sure HSD or Bob is running. +Copy .env.example to .env and fill in the details. + +Run the script: +```bash +python3 -m pip install -r requirements.txt +python3 renew.py +``` + +## ENV Variables +HSD and wallet variables are required. +```bash +API_KEY=hsd-api-key +ACCOUNT=wallet-name +PASSWORD=wallet-password +``` + +### Renewal types +There are 2 types of renewals, expiring and all. + +#### Expiring +This will renew all domains that are expiring within the next X days. +```bash +RENEW_TYPE=expiring +RENEW_DAYS=365 +``` + +#### All +This will renew all domains in the wallet. +```bash +RENEW_TYPE=all +``` \ No newline at end of file diff --git a/renew.py b/renew.py new file mode 100644 index 0000000..f5d19d3 --- /dev/null +++ b/renew.py @@ -0,0 +1,135 @@ +# Get env +import os +import sys +from dotenv import load_dotenv +import requests +import json +import subprocess + +load_dotenv() +api_key = os.getenv("API_KEY") +account = os.getenv("ACCOUNT") +password = os.getenv("PASSWORD") +renewType = os.getenv("RENEW_TYPE") +expireThreshold = 365 +if os.getenv("RENEW_DAYS") is not None: + try: + expireThreshold = int(os.getenv("RENEW_DAYS")) + except: + print("Invalid RENEW_DAYS value") + sys.exit() + +def escape_json_for_shell(json_data): + # Convert Python object to JSON string + json_string = json.dumps(json_data) + + # Escape special characters for shell usage + escaped_string = json_string.replace('\\', '\\\\') + escaped_string = escaped_string.replace('"', '\\"') + escaped_string = escaped_string.replace("'", "\\'") + escaped_string = escaped_string.replace('\n', '\\n') + escaped_string = escaped_string.replace('\r', '\\r') + escaped_string = escaped_string.replace('\t', '\\t') + escaped_string = escaped_string.replace(' ', '\\ ') + + return escaped_string + + +# Get the domain list +domainslist = [] +domainRequest = requests.get(f'http://x:{api_key}@127.0.0.1:12039/wallet/{account}/name?own=true') +if renewType == "all": + for domain in domainRequest.json(): + domainslist.append(domain["name"]) +elif renewType == "expiring": + for domain in domainRequest.json(): + if domain["stats"]["daysUntilExpire"] < expireThreshold: + domainslist.append(domain["name"]) + + +# Verify the domain list +print("Renewing the following domains:") +if len(domainslist) == 0: + print("No domains to renew") + sys.exit() + + +for domain in domainslist: + print(domain, end=" ") + +print("\nDo you want to edit the list? (y/n) ", end="") +editList = input() +if editList == "y": + while True: + print("Do you want to add or remove a domain or done? (a/r/d) ", end="") + action = input() + if action == "a": + print("Enter the domain you want to add:") + domain = input() + domainslist.append(domain) + elif action == "r": + print("Enter the domain you want to remove:") + domain = input() + domainslist.remove(domain) + else: + break + print("Renewing the following domains:") + for domain in domainslist: + print(domain, end=" ") + + +# Create the batch +batch = [] + +for domain in domainslist: + batch.append(f'["RENEW", "{domain}"]') + + +batchTX = "[" + ", ".join(batch) + "]" +responseContent = f'{{"method": "createbatch","params":[ {batchTX} ]}}' +print("Creating batch...") +response = requests.post(f'http://x:{api_key}@127.0.0.1:12039', data=responseContent) +if response.status_code != 200: + print("Failed to create batch") + print(response.json()) + sys.exit() + +batch = response.json() +# Verify the batch +print("Verifying batch...") +if batch["error"]: + if batch["error"] != "": + print("Failed to verify batch") + print(batch["error"]["message"]) + sys.exit() + +batch = json.dumps(batch) +domainslist = json.dumps(domainslist) + +# Send the batch +print("Sending batch to hsd...") + +command = [ + "hsd-ledger/bin/hsd-ledger", + "sendraw", + batch, + domainslist, + "--api-key", + api_key, + "-w", + account +] +try: + output = subprocess.run(command, capture_output=True, text=True) + print(output.stdout) + print(output.stderr) + + # Try to extract the txid + txid = output.stdout.split("Submitted TXID: ")[1].split("\n")[0] + print(f"https://niami.io/tx/{txid}") + +except Exception as e: + print(f"Error running command: {str(e)}") + sys.exit() + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3e338bf --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +python-dotenv \ No newline at end of file