Created
October 23, 2025 13:13
-
-
Save tundachef/485c26d61641fc88cf0dad5ca9d28be3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // searchPublicKeysFromDir.ts | |
| // Usage: | |
| // ts-node searchPublicKeysFromDir.ts --dir ./data | |
| // # or compile first: tsc searchPublicKeysFromDir.ts && node dist/searchPublicKeysFromDir.js --dir ./data | |
| // | |
| // What it does: | |
| // - Reads all .json files in the given folder | |
| // - Searches for any record with a `publicKey` matching one from publicKeysToFind | |
| // - Intentionally slow (configurable delays + jitter) | |
| // - Writes results to ./search-results.json | |
| import { promises as fs } from "fs"; | |
| import * as path from "path"; | |
| // ====== 1) PUT YOUR PUBLIC KEYS HERE (exact matches) ====== | |
| const publicKeysToFind: string[] = [ | |
| "3NRuvg1SghhNbQHTMmFVPCGX88zvS41YuuchFu5LpFm2", | |
| // "9kf7oyNPHZB7TWcZZRewFMFwGNDKSEZKSSumMdaRYiuv", | |
| // "BfrgGRQHaY7jXmGQUNa5zC3xAidJ9rEZ8jr32CyP2hXQ", | |
| ]; | |
| // ====== 2) SLOWDOWN SETTINGS (tweak as you like) ====== | |
| const delayPerFileMs = 800; // wait this long before processing each file | |
| const perItemDelayMs = 120; // wait this long between checking each record | |
| const jitterMs = 50; // +/- jitter to avoid uniform timing | |
| const recursive = false; // set true to scan subfolders too | |
| // ====== Types ====== | |
| type KeyRecord = { publicKey?: string; privateKey?: string; [k: string]: any }; | |
| type SearchResult = { file: string; index: number; record: KeyRecord }; | |
| // ====== Helpers ====== | |
| function sleep(ms: number) { | |
| return new Promise((res) => setTimeout(res, Math.max(0, Math.floor(ms)))); | |
| } | |
| function randomJitter() { | |
| return Math.floor((Math.random() * 2 - 1) * jitterMs); | |
| } | |
| function getArgValue(flag: string): string | null { | |
| const idx = process.argv.indexOf(flag); | |
| if (idx >= 0 && process.argv[idx + 1]) return process.argv[idx + 1]; | |
| return null; | |
| } | |
| // ====== Resolve directory to scan ====== | |
| const ROOT_DIR = getArgValue("--dir") ?? "./data"; | |
| // Build a Set for O(1) membership checks | |
| const targets = new Set(publicKeysToFind.filter(Boolean)); | |
| // ====== File discovery ====== | |
| async function listJsonFiles(dir: string): Promise<string[]> { | |
| const out: string[] = []; | |
| async function walk(current: string) { | |
| let entries: any[]; | |
| try { | |
| entries = await fs.readdir(current, { withFileTypes: true }); | |
| } catch (err) { | |
| console.error(`[ERR] cannot read dir ${current}: ${(err as Error).message}`); | |
| return; | |
| } | |
| for (const entry of entries) { | |
| const full = path.join(current, entry.name); | |
| if (entry.isDirectory()) { | |
| if (recursive) await walk(full); | |
| } else if (entry.isFile() && entry.name.toLowerCase().endsWith(".json")) { | |
| out.push(full); | |
| } | |
| } | |
| } | |
| await walk(path.resolve(dir)); | |
| return out; | |
| } | |
| // ====== Inspect one JSON file ====== | |
| async function inspectFile(filePath: string): Promise<SearchResult[]> { | |
| const results: SearchResult[] = []; | |
| let raw: string; | |
| try { | |
| raw = await fs.readFile(filePath, "utf8"); | |
| } catch (err) { | |
| console.error(`[ERR] cannot read ${filePath}: ${(err as Error).message}`); | |
| return results; | |
| } | |
| // Slow before-parse delay per file | |
| await sleep(delayPerFileMs + randomJitter()); | |
| let json: any; | |
| try { | |
| json = JSON.parse(raw); | |
| } catch (err) { | |
| console.error(`[ERR] invalid JSON in ${filePath}: ${(err as Error).message}`); | |
| return results; | |
| } | |
| // Accept either an array or a common wrapper object | |
| const candidates: KeyRecord[] = Array.isArray(json) ? json : (json.records || json.keys || json.items || []); | |
| if (!Array.isArray(candidates)) { | |
| console.warn(`[WARN] ${filePath} has no array at root/records/keys/items; skipping.`); | |
| return results; | |
| } | |
| for (let i = 0; i < candidates.length; i++) { | |
| const item = candidates[i]; | |
| // Slow per-item delay | |
| await sleep(perItemDelayMs + randomJitter()); | |
| if (!item || typeof item !== "object") continue; | |
| // Try common field names | |
| const pub = | |
| (item.publicKey ?? | |
| item.pub ?? | |
| item.address ?? | |
| item.owner) as string | undefined; | |
| if (!pub) continue; | |
| if (targets.has(pub)) { | |
| results.push({ file: filePath, index: i, record: item }); | |
| // If you want to stop on first match per file, uncomment next line: | |
| // break; | |
| } | |
| } | |
| return results; | |
| } | |
| // ====== Main ====== | |
| async function main() { | |
| if (targets.size === 0) { | |
| console.error("No public keys in publicKeysToFind. Add at least one and retry."); | |
| process.exit(2); | |
| } | |
| console.log(`Dir: ${ROOT_DIR}`); | |
| console.log(`Scanning for ${targets.size} publicKey(s):`); | |
| for (const k of targets) console.log(` - ${k}`); | |
| console.log(""); | |
| const files = await listJsonFiles(ROOT_DIR); | |
| if (files.length === 0) { | |
| console.log("No .json files found."); | |
| return; | |
| } | |
| console.log(`Found ${files.length} JSON file(s). Starting slow search...\n`); | |
| const allResults: SearchResult[] = []; | |
| // Serial on purpose (slow). Change to Promise.all for concurrent (still per-item slow). | |
| for (const f of files) { | |
| const res = await inspectFile(f); | |
| if (res.length) { | |
| console.log(`[FOUND] ${res.length} match(es) in ${f}`); | |
| for (const r of res) { | |
| console.log(` - index ${r.index}: ${JSON.stringify(r.record)}`); | |
| } | |
| } else { | |
| console.log(`[OK] no matches in ${f}`); | |
| } | |
| allResults.push(...res); | |
| } | |
| console.log("\nSearch complete."); | |
| console.log(`Total matches: ${allResults.length}`); | |
| try { | |
| await fs.writeFile("./search-results.json", JSON.stringify(allResults, null, 2), "utf8"); | |
| console.log("Wrote ./search-results.json"); | |
| } catch (err) { | |
| console.warn("Could not write results file:", (err as Error).message); | |
| } | |
| } | |
| main().catch((err) => { | |
| console.error("Fatal:", (err as Error).message); | |
| process.exit(1); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment