[object Object]

← back to Domain Sniper

register: refuse re-registration of domains in data/owned.json (exit 5)

ed0c01ff6594dd20ef8cf1ab06323a032fc39cec · 2026-05-12 18:32:48 -0700 · steve

Audit of register.js found DRY-RUN default, validated domain regex,
and no availability-leak codepath — all clean. One gap: the README
calls owned.json the single-source-of-truth for 'what we already
grabbed' but register.js was not actually consulting it.

Added alreadyOwned() check that loads data/owned.json (tolerates
either ["d.com",…] or {domains:[…]} shape, gracefully no-ops when
the file is absent). Hits before backend detection so a typo'd
re-register attempt fails fast with exit 5 — distinct from the
existing exit codes (2 usage, 3 no-creds, 4 reg-failed).

Verified: owned → exit 5 with red REFUSED banner; fresh → normal flow.

Files touched

Diff

commit ed0c01ff6594dd20ef8cf1ab06323a032fc39cec
Author: steve <steve@designerwallcoverings.com>
Date:   Tue May 12 18:32:48 2026 -0700

    register: refuse re-registration of domains in data/owned.json (exit 5)
    
    Audit of register.js found DRY-RUN default, validated domain regex,
    and no availability-leak codepath — all clean. One gap: the README
    calls owned.json the single-source-of-truth for 'what we already
    grabbed' but register.js was not actually consulting it.
    
    Added alreadyOwned() check that loads data/owned.json (tolerates
    either ["d.com",…] or {domains:[…]} shape, gracefully no-ops when
    the file is absent). Hits before backend detection so a typo'd
    re-register attempt fails fast with exit 5 — distinct from the
    existing exit codes (2 usage, 3 no-creds, 4 reg-failed).
    
    Verified: owned → exit 5 with red REFUSED banner; fresh → normal flow.
---
 register.js | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/register.js b/register.js
index 181542a..660c7f6 100644
--- a/register.js
+++ b/register.js
@@ -23,6 +23,20 @@ const path = require('path');
 
 const DATA_DIR = path.join(__dirname, 'data');
 const LOG_FILE = path.join(DATA_DIR, 'registrations.jsonl');
+const OWNED_FILE = path.join(DATA_DIR, 'owned.json');
+
+// Defensive: never re-register a domain Steve already owns. data/owned.json
+// is the single-source-of-truth list per the README. File may not exist yet —
+// in that case there's nothing to compare against, so allow the registration.
+function alreadyOwned(domain) {
+  if (!fs.existsSync(OWNED_FILE)) return false;
+  try {
+    const j = JSON.parse(fs.readFileSync(OWNED_FILE, 'utf8'));
+    const list = Array.isArray(j) ? j : (Array.isArray(j.domains) ? j.domains : []);
+    const target = domain.toLowerCase();
+    return list.some((d) => typeof d === 'string' && d.toLowerCase() === target);
+  } catch { return false; }
+}
 
 function detectBackend() {
   if (process.env.NAMESILO_API_KEY) return 'namesilo';
@@ -112,6 +126,11 @@ async function main() {
     console.error(`invalid domain syntax: ${domain}`);
     process.exit(2);
   }
+  if (alreadyOwned(domain)) {
+    console.error(`\n  \x1b[31mREFUSED:\x1b[0m ${domain} is in data/owned.json — already owned.`);
+    console.error(`  Remove it from owned.json first if you really intend to re-register.\n`);
+    process.exit(5);
+  }
 
   const backend = detectBackend();
 

← d315f31 ct-source-certspotter: mark both adapters STALLED with react  ·  back to Domain Sniper  ·  owned-check: extract shared module + extend safety to honeyp 46c5487 →