nukebase 2.0.5 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -857,7 +857,9 @@ async function deleteProject() {
857
857
  // nukebase domain remove disconnect it
858
858
  //
859
859
  // The guided flow is the dashboard's modal in the terminal: it prints the two
860
- // A records to create, polls DNS until both point here (Enter to check now,
860
+ // A records and the ownership TXT (nukebase.<domain> = nukebase-uid=<uid>,
861
+ // which the server requires on a domain's first connection so no other
862
+ // account can claim it) to create, polls DNS until they are in place (Enter to check now,
861
863
  // Ctrl+C to give up and come back later), then asks the server to verify and
862
864
  // issue the certificate — the slow part, up to a minute at Let's Encrypt.
863
865
  // --email is the cert contact; it defaults to the account email in
@@ -886,8 +888,9 @@ async function domainCommand() {
886
888
  if (sub) {
887
889
  if (args.has('wait')) {
888
890
  const ip = await regionIp();
889
- printDnsRecords(ip);
890
- await waitForDns(sub, ip);
891
+ const needTxt = (await currentDomain()) !== sub; // already ours: proven when connected
892
+ printDnsRecords(ip, needTxt);
893
+ await waitForDns(sub, ip, needTxt);
891
894
  }
892
895
  await connectDomain(sub, email);
893
896
  process.exit(0);
@@ -916,8 +919,8 @@ async function domainCommand() {
916
919
  if (!/^[a-z0-9.-]+\.[a-z]{2,}$/.test(domain)) { console.log(` "${domain}" does not look like a domain.`); domain = ''; }
917
920
  }
918
921
 
919
- printDnsRecords(ip);
920
- await waitForDns(domain, ip);
922
+ printDnsRecords(ip, true);
923
+ await waitForDns(domain, ip, true);
921
924
 
922
925
  // Step 3 — the server does the real verification and issues the cert.
923
926
  await connectDomain(domain, email);
@@ -962,12 +965,20 @@ async function regionIp() {
962
965
  return null;
963
966
  }
964
967
 
965
- function printDnsRecords(ip) {
968
+ // The ownership record the server checks on a domain's first connection.
969
+ const domainTxtValue = () => `nukebase-uid=${uid}`;
970
+
971
+ function printDnsRecords(ip, withTxt) {
966
972
  console.log('\n Step 1 — point it here. At your registrar (GoDaddy, Namecheap,');
967
973
  console.log(' Cloudflare, ...) add these DNS records:\n');
968
- console.log(' Type Name Value');
969
- console.log(` A @ ${ip || "(this region's IP — see the dashboard)"}`);
970
- console.log(` A www ${ip || '(same)'}`);
974
+ console.log(' Type Name Value');
975
+ console.log(` A @ ${ip || "(this region's IP — see the dashboard)"}`);
976
+ console.log(` A www ${ip || '(same)'}`);
977
+ if (withTxt) {
978
+ console.log(` TXT nukebase ${domainTxtValue()}`);
979
+ console.log('\n The TXT record proves the domain is yours, so no other account can');
980
+ console.log(' connect it. One on your main domain covers its subdomains too.');
981
+ }
971
982
  console.log('\n If you use Cloudflare, set the records to "DNS only" (grey cloud)');
972
983
  console.log(' so the certificate can be issued.\n');
973
984
  }
@@ -981,7 +992,7 @@ function printDnsRecords(ip) {
981
992
  // long after the server sees it — and on some Windows setups Node's own
982
993
  // resolver cannot reach the system DNS server at all (ECONNREFUSED on every
983
994
  // name). getaddrinfo is the fallback for a machine that blocks 1.1.1.1.
984
- async function waitForDns(domain, ip) {
995
+ async function waitForDns(domain, ip, needTxt) {
985
996
  console.log(' Step 2 — waiting for DNS. This can take a few minutes.');
986
997
  console.log(' Press Enter to check now, Ctrl+C to stop and come back later.\n');
987
998
  const dns = require('dns').promises;
@@ -990,19 +1001,31 @@ async function waitForDns(domain, ip) {
990
1001
  try { return await pub.resolve4(name); } catch (e) {}
991
1002
  try { return (await dns.lookup(name, { all: true, family: 4 })).map(a => a.address); } catch (e) { return []; }
992
1003
  };
993
- let apexOk = false, wwwOk = false;
1004
+ // Same rule as the server: nukebase.<domain>, then each parent.
1005
+ const want = domainTxtValue().toLowerCase();
1006
+ const txtFound = async () => {
1007
+ const labels = domain.split('.');
1008
+ for (let i = 0; i <= labels.length - 2; i++) {
1009
+ let recs;
1010
+ try { recs = await pub.resolveTxt('nukebase.' + labels.slice(i).join('.')); } catch (e) { continue; }
1011
+ if (recs.some(chunks => chunks.join('').trim().toLowerCase() === want)) return true;
1012
+ }
1013
+ return false;
1014
+ };
1015
+ let apexOk = false, wwwOk = false, txtOk = !needTxt;
994
1016
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
995
1017
  let poke = null;
996
1018
  rl.on('line', () => { if (poke) poke(); });
997
1019
  const wait = (ms) => new Promise(res => { poke = res; setTimeout(res, ms); });
998
1020
  try {
999
1021
  for (;;) {
1000
- const [apex, www] = await Promise.all([lookup(domain), lookup(`www.${domain}`)]);
1022
+ const [apex, www, txt] = await Promise.all([lookup(domain), lookup(`www.${domain}`), needTxt ? txtFound() : true]);
1001
1023
  apexOk = ip ? apex.includes(ip) : apex.length > 0;
1002
1024
  wwwOk = ip ? www.includes(ip) : www.length > 0;
1025
+ txtOk = txt;
1003
1026
  const mark = ok => ok ? '✓' : '…';
1004
- process.stdout.write(`\r ${mark(apexOk)} ${domain} ${apex.length ? '→ ' + apex.join(', ') : '(no record yet)'} ${mark(wwwOk)} www ${www.length ? '→ ' + www.join(', ') : '(no record yet)'} `);
1005
- if (apexOk) break;
1027
+ process.stdout.write(`\r ${mark(apexOk)} ${domain} ${apex.length ? '→ ' + apex.join(', ') : '(no record yet)'} ${mark(wwwOk)} www ${www.length ? '→ ' + www.join(', ') : '(no record yet)'}${needTxt ? ` ${mark(txtOk)} TXT ${txtOk ? 'found' : '(not yet)'}` : ''} `);
1028
+ if (apexOk && txtOk) break;
1006
1029
  await wait(15000);
1007
1030
  }
1008
1031
  } finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nukebase",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "NukeBase CLI: create, deploy and manage NukeBase projects",
5
5
  "bin": {
6
6
  "nukebase": "bin/nukebase.js"
@@ -17,6 +17,13 @@
17
17
  "ws": "^8.20.0"
18
18
  },
19
19
  "homepage": "https://nukebase.com",
20
- "keywords": ["nukebase", "database", "realtime", "hosting", "cli", "deploy"],
20
+ "keywords": [
21
+ "nukebase",
22
+ "database",
23
+ "realtime",
24
+ "hosting",
25
+ "cli",
26
+ "deploy"
27
+ ],
21
28
  "license": "MIT"
22
29
  }