apertodns 1.2.5 → 2.0.0

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.
Files changed (3) hide show
  1. package/README.md +63 -8
  2. package/index.js +2 -109
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -11,16 +11,19 @@ ApertoDNS is a free Dynamic DNS service that lets you point a subdomain to your
11
11
 
12
12
  ## Why ApertoDNS?
13
13
 
14
- | Feature | ApertoDNS | No-IP | DuckDNS | Dynu |
15
- |---------|-----------|-------|---------|------|
16
- | Free subdomains | Unlimited | 1 (free) | 5 | 4 |
17
- | API Keys with scopes | Yes | No | No | Limited |
14
+ | Feature | ApertoDNS | Dyn (Oracle) | No-IP | DuckDNS |
15
+ |---------|-----------|--------------|-------|---------|
16
+ | Free plan | Yes | No ($55/yr) | Yes | Yes |
17
+ | Free subdomains | Unlimited | 0 | 1 | 5 |
18
+ | API Keys with scopes | Yes | No | No | No |
18
19
  | CLI tool | Yes | No | No | No |
19
- | IPv6 support | Yes | Paid | Yes | Yes |
20
- | No forced renewal | Yes | 30 days | Yes | Yes |
21
- | DynDNS2 compatible | Yes | Yes | No | Yes |
20
+ | Docker images | Yes | No | No | No |
21
+ | IPv6 support | Yes | Paid | Paid | Yes |
22
+ | No forced renewal | Yes | N/A | 30 days | Yes |
23
+ | DynDNS2 compatible | Yes | Yes | Yes | No |
22
24
  | Webhooks | Yes | No | No | No |
23
25
  | Team sharing | Yes | No | No | No |
26
+ | Open Source | Yes | No | No | No |
24
27
 
25
28
  ## Features
26
29
 
@@ -33,6 +36,7 @@ ApertoDNS is a free Dynamic DNS service that lets you point a subdomain to your
33
36
  - **IPv4 & IPv6** - Full dual-stack support
34
37
  - **Real-time Stats** - View usage statistics and logs
35
38
  - **Router/NAS Compatible** - Works with Synology, QNAP, and DynDNS2-compatible routers
39
+ - **Docker Images** - Official [apertodns/cli](https://hub.docker.com/r/apertodns/cli) and [apertodns/updater](https://hub.docker.com/r/apertodns/updater) images
36
40
 
37
41
  ## Requirements
38
42
 
@@ -123,7 +127,15 @@ apertodns --force
123
127
  | `--config` | Edit configuration |
124
128
  | `--logout` | Remove local configuration |
125
129
  | `--force` | Force DNS update now |
126
- | `--update` | Standalone DynDNS2 update (with `--domain` and `--token`) |
130
+
131
+ ### Standalone Update (DynDNS2)
132
+
133
+ | Command | Description |
134
+ |---------|-------------|
135
+ | `--update` | Standalone DynDNS2 update (no config required) |
136
+ | `--domain <fqdn>` | Domain to update (with --update) |
137
+ | `--token <token>` | Token for authentication (with --update) |
138
+ | `--ip <address>` | Custom IP address (optional, auto-detected if omitted) |
127
139
 
128
140
  ### Daemon Mode
129
141
 
@@ -185,6 +197,49 @@ apertodns --daemon
185
197
  apertodns --daemon --interval 60
186
198
  ```
187
199
 
200
+ ## Standalone Update
201
+
202
+ Update DNS without any saved configuration - perfect for scripts and one-off updates:
203
+
204
+ ```bash
205
+ # Auto-detect IP and update
206
+ apertodns --update --domain myserver.apertodns.com --token YOUR_TOKEN
207
+
208
+ # Specify custom IP
209
+ apertodns --update --domain myserver.apertodns.com --token YOUR_TOKEN --ip 203.0.113.42
210
+ ```
211
+
212
+ ## Docker
213
+
214
+ Run without installing Node.js:
215
+
216
+ ```bash
217
+ # Run CLI via Docker
218
+ docker run --rm apertodns/cli --help
219
+
220
+ # Interactive setup (persisted config)
221
+ docker run -it -v apertodns_config:/root/.config/apertodns apertodns/cli --setup
222
+
223
+ # List domains
224
+ docker run -v apertodns_config:/root/.config/apertodns apertodns/cli --domains
225
+
226
+ # Standalone update (no config needed)
227
+ docker run --rm apertodns/cli --update --domain myhost.apertodns.com --token YOUR_TOKEN
228
+ ```
229
+
230
+ For continuous updates, use the dedicated updater image:
231
+
232
+ ```bash
233
+ docker run -d \
234
+ --name apertodns-updater \
235
+ --restart unless-stopped \
236
+ -e TOKEN=your_token \
237
+ -e DOMAINS=myhost.apertodns.com \
238
+ apertodns/updater
239
+ ```
240
+
241
+ See [Docker Hub](https://hub.docker.com/r/apertodns/cli) for more options.
242
+
188
243
  ## Automatic Updates (Cron)
189
244
 
190
245
  Set up automatic IP updates with cron:
package/index.js CHANGED
@@ -173,14 +173,6 @@ const daemonInterval = args.includes("--interval") ? parseInt(args[args.indexOf(
173
173
  const showMyIp = args.includes("--my-ip") || args.includes("--ip");
174
174
  const logout = args.includes("--logout");
175
175
 
176
- // Standalone update command (like docker updater)
177
- const standaloneUpdate = args.includes("--update");
178
- const updateDomain = args.includes("--domain") ? args[args.indexOf("--domain") + 1] : null;
179
- const updateToken = args.includes("--token") ? args[args.indexOf("--token") + 1] : null;
180
- const updateIp = args.includes("--ip") && args.indexOf("--ip") !== args.indexOf("--my-ip")
181
- ? args[args.indexOf("--ip") + 1]
182
- : null;
183
-
184
176
  // JSON output helper
185
177
  const jsonOutput = (data) => {
186
178
  if (showJson) {
@@ -234,12 +226,6 @@ ${chalk.bold("CONFIGURAZIONE:")}
234
226
  ${cyan("--logout")} Rimuovi configurazione locale
235
227
  ${cyan("--force")} Forza aggiornamento DNS
236
228
 
237
- ${chalk.bold("AGGIORNAMENTO STANDALONE:")}
238
- ${cyan("--update")} Aggiorna DNS via DynDNS2 (richiede --domain e --token)
239
- ${cyan("--domain")} <name> Dominio da aggiornare (es: myhost.apertodns.com)
240
- ${cyan("--token")} <token> Token DDNS per l'autenticazione
241
- ${cyan("--ip")} <ip> IP da impostare (opzionale, auto-detect se omesso)
242
-
243
229
  ${chalk.bold("DAEMON MODE:")}
244
230
  ${cyan("--daemon")} Avvia in modalità daemon (aggiornamento continuo)
245
231
  ${cyan("--interval")} <sec> Intervallo aggiornamento daemon (default: 300s)
@@ -267,8 +253,6 @@ ${gray("Esempi:")}
267
253
  ${gray("$")} apertodns --test mioserver.apertodns.com
268
254
  ${gray("$")} apertodns --daemon --interval 60
269
255
  ${gray("$")} apertodns --api-key ak_xxx... --domains --json
270
- ${gray("$")} apertodns --update --domain myhost.apertodns.com --token abc123
271
- ${gray("$")} apertodns --update --domain myhost.apertodns.com --token abc123 --ip 1.2.3.4
272
256
 
273
257
  ${gray("Docs: https://apertodns.com/docs")}
274
258
  `);
@@ -318,8 +302,8 @@ const spinner = (text) => ora({ text, spinner: "dots", color: "yellow" });
318
302
 
319
303
  // Helper: get auth headers (supports both JWT and API Key)
320
304
  const getAuthHeaders = (token) => {
321
- // API Keys start with "ak_"
322
- if (token && token.startsWith('ak_')) {
305
+ // API Keys start with "ak_" or "apertodns_live_" or "apertodns_test_"
306
+ if (token && (token.startsWith('ak_') || token.startsWith('apertodns_live_') || token.startsWith('apertodns_test_'))) {
323
307
  return { 'X-API-Key': token };
324
308
  }
325
309
  return { Authorization: `Bearer ${token}` };
@@ -1602,96 +1586,6 @@ const runDaemonMode = async () => {
1602
1586
  setInterval(update, daemonInterval * 1000);
1603
1587
  };
1604
1588
 
1605
- // ==================== STANDALONE UPDATE (DynDNS2) ====================
1606
-
1607
- const runStandaloneUpdate = async (domain, token, customIp) => {
1608
- // Validate required parameters
1609
- if (!domain || !token) {
1610
- if (showJson) {
1611
- console.log(JSON.stringify({
1612
- error: "Parametri mancanti. Usa: --update --domain <domain> --token <token> [--ip <ip>]"
1613
- }));
1614
- } else {
1615
- console.log(red("\n❌ Parametri mancanti."));
1616
- console.log(gray(" Uso: apertodns --update --domain <domain> --token <token> [--ip <ip>]\n"));
1617
- }
1618
- process.exit(1);
1619
- }
1620
-
1621
- const spin = !showJson ? spinner("Aggiornamento DNS via DynDNS2...").start() : null;
1622
-
1623
- try {
1624
- // Get current IP if not provided
1625
- let ipToUse = customIp;
1626
- if (!ipToUse) {
1627
- if (spin) spin.text = "Rilevamento IP pubblico...";
1628
- ipToUse = await getCurrentIP('https://api.ipify.org');
1629
- if (!ipToUse) {
1630
- throw new Error("Impossibile rilevare IP pubblico");
1631
- }
1632
- ipToUse = ipToUse.trim();
1633
- }
1634
-
1635
- if (spin) spin.text = `Aggiornamento ${domain} → ${ipToUse}...`;
1636
-
1637
- // Build DynDNS2 URL
1638
- const updateUrl = `https://api.apertodns.com/nic/update?hostname=${encodeURIComponent(domain)}&myip=${encodeURIComponent(ipToUse)}`;
1639
-
1640
- // Make request with Basic Auth (DynDNS2 protocol)
1641
- const authHeader = 'Basic ' + Buffer.from(`${domain}:${token}`).toString('base64');
1642
-
1643
- const res = await fetch(updateUrl, {
1644
- method: 'GET',
1645
- headers: {
1646
- 'Authorization': authHeader,
1647
- 'User-Agent': `ApertoDNS-CLI/${CURRENT_VERSION}`
1648
- }
1649
- });
1650
-
1651
- const responseText = await res.text();
1652
-
1653
- // Parse DynDNS2 response
1654
- const isSuccess = responseText.startsWith('good') || responseText.startsWith('nochg');
1655
-
1656
- if (isSuccess) {
1657
- spin?.succeed(`DNS aggiornato! ${domain} → ${ipToUse}`);
1658
-
1659
- if (showJson) {
1660
- console.log(JSON.stringify({
1661
- success: true,
1662
- domain,
1663
- ip: ipToUse,
1664
- response: responseText.trim(),
1665
- timestamp: new Date().toISOString()
1666
- }, null, 2));
1667
- } else if (!isCron) {
1668
- console.log(` ${gray('Risposta:')} ${green(responseText.trim())}`);
1669
- console.log();
1670
- }
1671
- } else {
1672
- spin?.fail(`Errore aggiornamento: ${responseText.trim()}`);
1673
-
1674
- if (showJson) {
1675
- console.log(JSON.stringify({
1676
- success: false,
1677
- domain,
1678
- ip: ipToUse,
1679
- error: responseText.trim(),
1680
- timestamp: new Date().toISOString()
1681
- }, null, 2));
1682
- }
1683
- process.exit(1);
1684
- }
1685
- } catch (err) {
1686
- spin?.fail(`Errore: ${err.message}`);
1687
-
1688
- if (showJson) {
1689
- console.log(JSON.stringify({ error: err.message }));
1690
- }
1691
- process.exit(1);
1692
- }
1693
- };
1694
-
1695
1589
  // ==================== LOGOUT ====================
1696
1590
 
1697
1591
  const runLogout = async () => {
@@ -1804,7 +1698,6 @@ const interactiveMode = async () => {
1804
1698
  const main = async () => {
1805
1699
  try {
1806
1700
  if (logout) await runLogout();
1807
- else if (standaloneUpdate) await runStandaloneUpdate(updateDomain, updateToken, updateIp);
1808
1701
  else if (showMyIp) await showMyIpCommand();
1809
1702
  else if (runDaemon) await runDaemonMode();
1810
1703
  else if (enableTokenId) await updateTokenState(enableTokenId, true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apertodns",
3
- "version": "1.2.5",
3
+ "version": "2.0.0",
4
4
  "description": "ApertoDNS CLI - Dynamic DNS management from your terminal. Manage domains, tokens, API keys and DNS updates with style.",
5
5
  "main": "index.js",
6
6
  "type": "module",