cloudflare-ddns-sync 2.0.5 → 3.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.
- package/CHANGELOG.md +14 -0
- package/README.md +34 -32
- package/dist/contracts/Auth.d.ts +5 -0
- package/dist/contracts/Auth.js +1 -0
- package/dist/contracts/Callbacks.d.ts +3 -3
- package/dist/contracts/Callbacks.js +1 -2
- package/dist/contracts/DomainRecordList.d.ts +2 -2
- package/dist/contracts/DomainRecordList.js +1 -2
- package/dist/contracts/Record.d.ts +4 -2
- package/dist/contracts/Record.js +1 -2
- package/dist/contracts/ZoneMap.d.ts +1 -1
- package/dist/contracts/ZoneMap.js +1 -2
- package/dist/contracts/cloudflare/RecordData.d.ts +4 -3
- package/dist/contracts/cloudflare/RecordData.js +1 -2
- package/dist/contracts/cloudflare/ZoneData.d.ts +1 -1
- package/dist/contracts/cloudflare/ZoneData.js +1 -2
- package/dist/contracts/cloudflare/index.d.ts +2 -2
- package/dist/contracts/cloudflare/index.js +2 -14
- package/dist/contracts/index.d.ts +6 -5
- package/dist/contracts/index.js +6 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.js +13 -29
- package/dist/lib/cloudflare-client.d.ts +2 -2
- package/dist/lib/cloudflare-client.js +58 -58
- package/dist/lib/cron.js +5 -11
- package/dist/lib/ip-utils.d.ts +1 -1
- package/dist/lib/ip-utils.js +10 -40
- package/package.json +19 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3
|
|
4
|
+
|
|
5
|
+
### v3.0.0
|
|
6
|
+
|
|
7
|
+
**This package will now be released as native ECMAScript module.**
|
|
8
|
+
|
|
9
|
+
- ✨ **Add possibility to use Cloudflare API Token**
|
|
10
|
+
- ♻️ Reduce request if many DNS Records exist for one Zone
|
|
11
|
+
- ⬆️ Update dependencies
|
|
12
|
+
|
|
3
13
|
## v2
|
|
4
14
|
|
|
15
|
+
### v2.0.6
|
|
16
|
+
|
|
17
|
+
- ⬆️ Update dependencies
|
|
18
|
+
|
|
5
19
|
### v2.0.5
|
|
6
20
|
|
|
7
21
|
- 🚨 Replace tslint with eslint
|
package/README.md
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/cloudflare-ddns-sync)
|
|
6
6
|
[](https://www.npmjs.com/package/cloudflare-ddns-sync-cli)
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
## Overview
|
|
10
9
|
|
|
11
10
|
Cloudflare-DDNS-Sync is a simple module that updates Cloudflare DNS records.
|
|
12
11
|
|
|
13
|
-
For a more detailed overview, have a look at the [Documentation](https://cddnss.knaup.
|
|
12
|
+
For a more detailed overview, have a look at the [Documentation](https://cddnss.knaup.pw/)
|
|
14
13
|
|
|
15
14
|
You may also have a look at the **official** [CLI version](https://www.npmjs.com/package/cloudflare-ddns-sync-cli) of Cloudflare-DDNS-Sync.
|
|
16
15
|
|
|
@@ -18,7 +17,7 @@ You may also have a look at the **official** [CLI version](https://www.npmjs.com
|
|
|
18
17
|
|
|
19
18
|
### Prerequisites
|
|
20
19
|
|
|
21
|
-
- Node
|
|
20
|
+
- Node (16, 18)
|
|
22
21
|
- Cloudflare Account
|
|
23
22
|
|
|
24
23
|
### Installation
|
|
@@ -34,27 +33,27 @@ in your project folder.
|
|
|
34
33
|
## Usage
|
|
35
34
|
|
|
36
35
|
> Hint: If a record is not existing, CDS will automatically create it when
|
|
37
|
-
syncing.
|
|
36
|
+
> syncing.
|
|
38
37
|
|
|
39
38
|
### Javascript Example
|
|
40
39
|
|
|
41
40
|
```javascript
|
|
42
|
-
const Cddnss = require(
|
|
41
|
+
const Cddnss = require("cloudflare-ddns-sync").default;
|
|
43
42
|
|
|
44
|
-
const cddnss = new Cddnss(
|
|
43
|
+
const cddnss = new Cddnss("your@email.com", "<your-cloudflare-api-key>");
|
|
45
44
|
|
|
46
45
|
const records = [
|
|
47
46
|
{
|
|
48
|
-
name:
|
|
49
|
-
type:
|
|
50
|
-
proxied: true,
|
|
51
|
-
ttl: 1,
|
|
52
|
-
priority: 0,
|
|
53
|
-
content:
|
|
47
|
+
name: "test-1.domain.com",
|
|
48
|
+
type: "A", // optional
|
|
49
|
+
proxied: true, // optional
|
|
50
|
+
ttl: 1, // optional
|
|
51
|
+
priority: 0, // optional
|
|
52
|
+
content: "1.2.3.4", // optional
|
|
54
53
|
},
|
|
55
54
|
{
|
|
56
|
-
name: "test-2.domain.com"
|
|
57
|
-
}
|
|
55
|
+
name: "test-2.domain.com",
|
|
56
|
+
},
|
|
58
57
|
];
|
|
59
58
|
|
|
60
59
|
cddnss.syncRecords(records).then((result) => {
|
|
@@ -65,21 +64,24 @@ cddnss.syncRecords(records).then((result) => {
|
|
|
65
64
|
### Typescript Example
|
|
66
65
|
|
|
67
66
|
```typescript
|
|
68
|
-
import Cddnss, {Record, RecordData} from
|
|
67
|
+
import Cddnss, { Record, RecordData } from "cloudflare-ddns-sync";
|
|
69
68
|
|
|
70
|
-
const cddnss: Cddnss = new Cddnss(
|
|
69
|
+
const cddnss: Cddnss = new Cddnss(
|
|
70
|
+
"your@email.com",
|
|
71
|
+
"<your-cloudflare-api-key>"
|
|
72
|
+
);
|
|
71
73
|
|
|
72
74
|
const records: Array<Record> = [
|
|
73
75
|
{
|
|
74
|
-
name:
|
|
75
|
-
type:
|
|
76
|
-
proxied: true,
|
|
77
|
-
ttl: 1,
|
|
78
|
-
priority: 0,
|
|
79
|
-
content:
|
|
76
|
+
name: "test-1.yourdomain.com",
|
|
77
|
+
type: "A", // optional
|
|
78
|
+
proxied: true, // optional
|
|
79
|
+
ttl: 1, // optional
|
|
80
|
+
priority: 0, // optional
|
|
81
|
+
content: "1.2.3.4", // optional
|
|
80
82
|
},
|
|
81
83
|
{
|
|
82
|
-
name: "test-2.yourdomain.com"
|
|
84
|
+
name: "test-2.yourdomain.com",
|
|
83
85
|
},
|
|
84
86
|
];
|
|
85
87
|
|
|
@@ -108,18 +110,18 @@ Cron expressions have the following syntax:
|
|
|
108
110
|
|
|
109
111
|
- getIp(): Promise\<string\>
|
|
110
112
|
- getIpv6(): Promise\<string\>
|
|
111
|
-
- getRecordDataForDomain(domain: string): Promise\<Array\<[RecordData](https://cddnss.knaup.
|
|
112
|
-
- getRecordDataForDomains(domains: Array\<string\>): Promise\<[DomainRecordList](https://cddnss.knaup.
|
|
113
|
-
- getRecordDataForRecord(record: [Record](https://cddnss.knaup.
|
|
114
|
-
- getRecordDataForRecords(records: Array\<[Record](https://cddnss.knaup.
|
|
113
|
+
- getRecordDataForDomain(domain: string): Promise\<Array\<[RecordData](https://cddnss.knaup.pw/types/recorddata)\>\>
|
|
114
|
+
- getRecordDataForDomains(domains: Array\<string\>): Promise\<[DomainRecordList](https://cddnss.knaup.pw/types/domainrecordlist)\>
|
|
115
|
+
- getRecordDataForRecord(record: [Record](https://cddnss.knaup.pw/types/record)): Promise\<[RecordData](https://cddnss.knaup.pw/types/recorddata)\>
|
|
116
|
+
- getRecordDataForRecords(records: Array\<[Record](https://cddnss.knaup.pw/types/record)\>): Promise\<Array\<[RecordData](https://cddnss.knaup.pw/types/recorddata)\>\>
|
|
115
117
|
- removeRecord(recordName: string, recordType?: string): Promise\<void\>
|
|
116
118
|
- stopSyncOnIpChange(changeListenerId: string): void
|
|
117
|
-
- syncByCronTime(cronExpression: string, records: Array\<[Record](https://cddnss.knaup.
|
|
118
|
-
- syncOnIpChange(records: Array\<[Record](https://cddnss.knaup.
|
|
119
|
-
- syncRecord(record: [Record](https://cddnss.knaup.
|
|
120
|
-
- syncRecords(records: Array\<[Record](https://cddnss.knaup.
|
|
119
|
+
- syncByCronTime(cronExpression: string, records: Array\<[Record](https://cddnss.knaup.pw/types/recorddata)\>, callback: [MultiSyncCallback](https://cddnss.knaup.pw/types/multisynccallback), ip?: string): [ScheduledTask](https://www.npmjs.com/package/node-cron#scheduledtask-methods)
|
|
120
|
+
- syncOnIpChange(records: Array\<[Record](https://cddnss.knaup.pw/types/record)\>, callback: multisynccallback): Promise\<string\>
|
|
121
|
+
- syncRecord(record: [Record](https://cddnss.knaup.pw/types/record), ip?: string): Promise\<[RecordData](https://cddnss.knaup.pw/types/recorddata)\>
|
|
122
|
+
- syncRecords(records: Array\<[Record](https://cddnss.knaup.pw/types/record)\>, ip?: string): Promise\<Array\<[RecordData](https://cddnss.knaup.pw/types/recorddata)\>\>
|
|
121
123
|
|
|
122
|
-
For a more detailed view, have a look at the [Documentation](https://cddnss.knaup.
|
|
124
|
+
For a more detailed view, have a look at the [Documentation](https://cddnss.knaup.pw/)
|
|
123
125
|
|
|
124
126
|
## Get Your Cloudflare API Key
|
|
125
127
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { RecordData } from './index';
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
import { RecordData } from './index.js';
|
|
2
|
+
export type SingleSyncCallback = (syncResult: RecordData) => void;
|
|
3
|
+
export type MultiSyncCallback = (syncResult: Array<RecordData>) => void;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { RecordTypes as CloudflareRecordTypes } from 'cloudflare';
|
|
2
|
+
export type RecordTypes = Exclude<CloudflareRecordTypes, 'MX' | 'SRV' | 'URI'>;
|
|
3
|
+
export type Record = {
|
|
2
4
|
name: string;
|
|
3
|
-
type?:
|
|
5
|
+
type?: RecordTypes;
|
|
4
6
|
proxied?: boolean;
|
|
5
7
|
ttl?: number;
|
|
6
8
|
priority?: number;
|
package/dist/contracts/Record.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type ZoneMap = Map<string, string>;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { RecordTypes } from '../index.js';
|
|
2
|
+
export type RecordData = {
|
|
2
3
|
id: string;
|
|
3
|
-
type:
|
|
4
|
+
type: RecordTypes;
|
|
4
5
|
name: string;
|
|
5
6
|
content: string;
|
|
6
7
|
proxiable: boolean;
|
|
@@ -13,7 +14,7 @@ export declare type RecordData = {
|
|
|
13
14
|
created_on: string;
|
|
14
15
|
meta: RecordMetaData;
|
|
15
16
|
};
|
|
16
|
-
export
|
|
17
|
+
export type RecordMetaData = {
|
|
17
18
|
auto_added: boolean;
|
|
18
19
|
managed_by_apps: boolean;
|
|
19
20
|
managed_by_argo_tunnel: boolean;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './RecordData';
|
|
2
|
-
export * from './ZoneData';
|
|
1
|
+
export * from './RecordData.js';
|
|
2
|
+
export * from './ZoneData.js';
|
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./RecordData"), exports);
|
|
14
|
-
__exportStar(require("./ZoneData"), exports);
|
|
1
|
+
export * from './RecordData.js';
|
|
2
|
+
export * from './ZoneData.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from './cloudflare/index';
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
1
|
+
export * from './cloudflare/index.js';
|
|
2
|
+
export * from './Auth.js';
|
|
3
|
+
export * from './Callbacks.js';
|
|
4
|
+
export * from './DomainRecordList.js';
|
|
5
|
+
export * from './Record.js';
|
|
6
|
+
export * from './ZoneMap.js';
|
package/dist/contracts/index.js
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./cloudflare/index"), exports);
|
|
14
|
-
__exportStar(require("./Callbacks"), exports);
|
|
15
|
-
__exportStar(require("./DomainRecordList"), exports);
|
|
16
|
-
__exportStar(require("./Record"), exports);
|
|
17
|
-
__exportStar(require("./ZoneMap"), exports);
|
|
1
|
+
export * from './cloudflare/index.js';
|
|
2
|
+
export * from './Auth.js';
|
|
3
|
+
export * from './Callbacks.js';
|
|
4
|
+
export * from './DomainRecordList.js';
|
|
5
|
+
export * from './Record.js';
|
|
6
|
+
export * from './ZoneMap.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ScheduledTask } from 'node-cron';
|
|
2
|
-
import { DomainRecordList, MultiSyncCallback, Record, RecordData } from './contracts/index';
|
|
2
|
+
import { Auth, DomainRecordList, MultiSyncCallback, Record, RecordData } from './contracts/index.js';
|
|
3
3
|
export default class CloudflareDDNSSync {
|
|
4
4
|
private cloudflareClient;
|
|
5
|
-
constructor(
|
|
5
|
+
constructor(auth: Auth);
|
|
6
6
|
getIp(): Promise<string>;
|
|
7
7
|
getIpv6(): Promise<string>;
|
|
8
8
|
getRecordDataForDomain(domain: string): Promise<Array<RecordData>>;
|
|
@@ -16,4 +16,4 @@ export default class CloudflareDDNSSync {
|
|
|
16
16
|
syncRecord(record: Record, ip?: string): Promise<RecordData>;
|
|
17
17
|
syncRecords(records: Array<Record>, ip?: string): Promise<Array<RecordData>>;
|
|
18
18
|
}
|
|
19
|
-
export * from './contracts/index';
|
|
19
|
+
export * from './contracts/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
-
};
|
|
15
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
const cloudflare_client_1 = __importDefault(require("./lib/cloudflare-client"));
|
|
17
|
-
const cron_1 = __importDefault(require("./lib/cron"));
|
|
18
|
-
const ip_utils_1 = __importDefault(require("./lib/ip-utils"));
|
|
19
|
-
class CloudflareDDNSSync {
|
|
1
|
+
import CloudflareClient from './lib/cloudflare-client.js';
|
|
2
|
+
import Cron from './lib/cron.js';
|
|
3
|
+
import ipUtils from './lib/ip-utils.js';
|
|
4
|
+
export default class CloudflareDDNSSync {
|
|
20
5
|
cloudflareClient;
|
|
21
|
-
constructor(
|
|
22
|
-
this.cloudflareClient = new
|
|
6
|
+
constructor(auth) {
|
|
7
|
+
this.cloudflareClient = new CloudflareClient(auth);
|
|
23
8
|
}
|
|
24
9
|
getIp() {
|
|
25
|
-
return
|
|
10
|
+
return ipUtils.getIpv4();
|
|
26
11
|
}
|
|
27
12
|
getIpv6() {
|
|
28
|
-
return
|
|
13
|
+
return ipUtils.getIpv6();
|
|
29
14
|
}
|
|
30
15
|
getRecordDataForDomain(domain) {
|
|
31
16
|
return this.cloudflareClient.getRecordDataForDomain(domain);
|
|
@@ -43,21 +28,21 @@ class CloudflareDDNSSync {
|
|
|
43
28
|
return this.cloudflareClient.removeRecordByNameAndType(recordName, recordType);
|
|
44
29
|
}
|
|
45
30
|
stopSyncOnIpChange(changeListenerId) {
|
|
46
|
-
|
|
31
|
+
ipUtils.removeIpChangeListener(changeListenerId);
|
|
47
32
|
}
|
|
48
33
|
syncByCronTime(cronExpression, records, callback, ip) {
|
|
49
|
-
return
|
|
34
|
+
return Cron.createCronJob(cronExpression, async () => {
|
|
50
35
|
const result = await this.syncRecords(records, ip);
|
|
51
36
|
callback(result);
|
|
52
37
|
});
|
|
53
38
|
}
|
|
54
39
|
async syncOnIpChange(records, callback) {
|
|
55
|
-
const changeListenerId = await
|
|
40
|
+
const changeListenerId = await ipUtils.addIpChangeListener(async (ip) => {
|
|
56
41
|
const result = await this.syncRecords(records, ip);
|
|
57
42
|
callback(result);
|
|
58
43
|
});
|
|
59
44
|
// Sync records to make sure the current ip is already set.
|
|
60
|
-
const currentIp = await
|
|
45
|
+
const currentIp = await ipUtils.getIpv4();
|
|
61
46
|
this.syncRecords(records, currentIp).then((syncedRecords) => {
|
|
62
47
|
callback(syncedRecords);
|
|
63
48
|
});
|
|
@@ -70,5 +55,4 @@ class CloudflareDDNSSync {
|
|
|
70
55
|
return this.cloudflareClient.syncRecords(records, ip);
|
|
71
56
|
}
|
|
72
57
|
}
|
|
73
|
-
|
|
74
|
-
__exportStar(require("./contracts/index"), exports);
|
|
58
|
+
export * from './contracts/index.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DomainRecordList, Record, RecordData } from '../contracts';
|
|
1
|
+
import { Auth, DomainRecordList, Record, RecordData } from '../contracts/index.js';
|
|
2
2
|
export default class CloudflareClient {
|
|
3
3
|
private cloudflare;
|
|
4
4
|
private zoneMap;
|
|
5
|
-
constructor(
|
|
5
|
+
constructor(auth: Auth);
|
|
6
6
|
syncRecord(record: Record, ip?: string): Promise<RecordData>;
|
|
7
7
|
syncRecords(records: Array<Record>, ip?: string): Promise<Array<RecordData>>;
|
|
8
8
|
removeRecordByNameAndType(recordName: string, recordType?: string): Promise<void>;
|
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const parse_domain_1 = require("parse-domain");
|
|
7
|
-
const cloudflare_1 = __importDefault(require("cloudflare"));
|
|
8
|
-
const ip_utils_1 = __importDefault(require("./ip-utils"));
|
|
1
|
+
import { ParseResultType, fromUrl, parseDomain, } from 'parse-domain';
|
|
2
|
+
import Cloudflare from 'cloudflare';
|
|
3
|
+
import IPUtils from './ip-utils.js';
|
|
9
4
|
const ipv4Regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/u;
|
|
10
5
|
// eslint-disable-next-line max-len
|
|
11
6
|
const ipv6Regex = /^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-fA-F]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,1}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,2}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,3}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:[0-9a-fA-F]{1,4})):)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,4}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,5}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,6}(?:(?:[0-9a-fA-F]{1,4})))?::))))$/u;
|
|
12
|
-
class CloudflareClient {
|
|
7
|
+
export default class CloudflareClient {
|
|
13
8
|
cloudflare;
|
|
14
9
|
zoneMap = new Map();
|
|
15
|
-
constructor(
|
|
16
|
-
this.cloudflare = new
|
|
17
|
-
email: email,
|
|
18
|
-
key: authKey,
|
|
19
|
-
});
|
|
10
|
+
constructor(auth) {
|
|
11
|
+
this.cloudflare = new Cloudflare(auth);
|
|
20
12
|
this.updateZoneMap();
|
|
21
13
|
}
|
|
22
14
|
async syncRecord(record, ip) {
|
|
23
15
|
const recordIds = await this.getRecordIdsForRecords([record]);
|
|
24
|
-
const ipToUse = ip ? ip : await
|
|
16
|
+
const ipToUse = ip ? ip : await IPUtils.getIpv4();
|
|
25
17
|
const zoneId = await this.getZoneIdByRecordName(record.name);
|
|
26
18
|
const recordId = recordIds.get(this.getRecordIdMapKey(record));
|
|
27
19
|
const recordExists = recordId !== undefined;
|
|
@@ -34,7 +26,7 @@ class CloudflareClient {
|
|
|
34
26
|
}
|
|
35
27
|
async syncRecords(records, ip) {
|
|
36
28
|
const recordIds = await this.getRecordIdsForRecords(records);
|
|
37
|
-
const ipToUse = ip ? ip : await
|
|
29
|
+
const ipToUse = ip ? ip : await IPUtils.getIpv4();
|
|
38
30
|
const resultPromises = records.map(async (record) => {
|
|
39
31
|
const zoneId = await this.getZoneIdByRecordName(record.name);
|
|
40
32
|
const recordId = recordIds.get(this.getRecordIdMapKey(record));
|
|
@@ -53,7 +45,7 @@ class CloudflareClient {
|
|
|
53
45
|
const recordTypeToUse = recordType ? recordType : 'A';
|
|
54
46
|
const zoneId = await this.getZoneIdByRecordName(recordName);
|
|
55
47
|
const recordId = await this.getRecordIdByNameAndType(recordName, recordTypeToUse);
|
|
56
|
-
|
|
48
|
+
await this.cloudflare.dnsRecords.del(zoneId, recordId);
|
|
57
49
|
}
|
|
58
50
|
async getRecordDataForRecord(record) {
|
|
59
51
|
const domain = this.getDomainByRecordName(record.name);
|
|
@@ -88,57 +80,63 @@ class CloudflareClient {
|
|
|
88
80
|
return recordData;
|
|
89
81
|
}
|
|
90
82
|
async createRecord(zoneId, record, ip) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
const dnsRecord = {
|
|
84
|
+
...record,
|
|
85
|
+
name: record.name.toLowerCase(),
|
|
86
|
+
content: record.content ? record.content : ip,
|
|
87
|
+
type: record.type ? record.type : 'A',
|
|
88
|
+
ttl: record.ttl ? record.ttl : 1,
|
|
89
|
+
};
|
|
90
|
+
if (!dnsRecord.content) {
|
|
91
|
+
throw Error(`Could not create Record "${dnsRecord.name}": Content is missing!`);
|
|
92
|
+
}
|
|
93
|
+
if (dnsRecord.type === 'A') {
|
|
94
|
+
if (!dnsRecord.content.match(ipv4Regex)) {
|
|
95
|
+
throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv4!`);
|
|
101
96
|
}
|
|
102
97
|
}
|
|
103
|
-
else if (
|
|
104
|
-
if (!
|
|
105
|
-
throw Error(`Could not create Record "${
|
|
98
|
+
else if (dnsRecord.type === 'AAAA') {
|
|
99
|
+
if (!dnsRecord.content.match(ipv6Regex)) {
|
|
100
|
+
throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv6!`);
|
|
106
101
|
}
|
|
107
102
|
}
|
|
108
|
-
else if (
|
|
109
|
-
const parsedDomain =
|
|
110
|
-
if (parsedDomain.type !==
|
|
111
|
-
throw Error(`Could not create Record "${
|
|
103
|
+
else if (dnsRecord.type === 'CNAME') {
|
|
104
|
+
const parsedDomain = parseDomain(fromUrl(dnsRecord.content));
|
|
105
|
+
if (parsedDomain.type !== ParseResultType.Listed || !parsedDomain.domain) {
|
|
106
|
+
throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid domain name!`);
|
|
112
107
|
}
|
|
113
108
|
}
|
|
114
|
-
const response = await this.cloudflare.dnsRecords.add(zoneId,
|
|
109
|
+
const response = await this.cloudflare.dnsRecords.add(zoneId, dnsRecord);
|
|
115
110
|
return response.result;
|
|
116
111
|
}
|
|
117
112
|
async updateRecord(zoneId, recordId, record, ip) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
113
|
+
const dnsRecord = {
|
|
114
|
+
...record,
|
|
115
|
+
name: record.name.toLowerCase(),
|
|
116
|
+
content: record.content ? record.content : ip,
|
|
117
|
+
type: record.type ? record.type : 'A',
|
|
118
|
+
ttl: record.ttl ? record.ttl : 1,
|
|
119
|
+
};
|
|
120
|
+
if (!dnsRecord.content) {
|
|
121
|
+
throw Error(`Could not update Record "${dnsRecord.name}": Content is missing!`);
|
|
122
|
+
}
|
|
123
|
+
if (dnsRecord.type === 'A') {
|
|
124
|
+
if (!dnsRecord.content.match(ipv4Regex)) {
|
|
125
|
+
throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv4!`);
|
|
128
126
|
}
|
|
129
127
|
}
|
|
130
|
-
else if (
|
|
131
|
-
if (!
|
|
132
|
-
throw Error(`Could not update Record "${
|
|
128
|
+
else if (dnsRecord.type === 'AAAA') {
|
|
129
|
+
if (!dnsRecord.content.match(ipv6Regex)) {
|
|
130
|
+
throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv6!`);
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
|
-
else if (
|
|
136
|
-
const parsedDomain =
|
|
137
|
-
if (parsedDomain.type !==
|
|
138
|
-
throw Error(`Could not update Record "${
|
|
133
|
+
else if (dnsRecord.type === 'CNAME') {
|
|
134
|
+
const parsedDomain = parseDomain(fromUrl(dnsRecord.content));
|
|
135
|
+
if (parsedDomain.type !== ParseResultType.Listed || !parsedDomain.domain) {
|
|
136
|
+
throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid domain name!`);
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
|
-
const response = await this.cloudflare.dnsRecords.edit(zoneId, recordId,
|
|
139
|
+
const response = await this.cloudflare.dnsRecords.edit(zoneId, recordId, dnsRecord);
|
|
142
140
|
return response.result;
|
|
143
141
|
}
|
|
144
142
|
async updateZoneMap() {
|
|
@@ -186,13 +184,16 @@ class CloudflareClient {
|
|
|
186
184
|
const records = [];
|
|
187
185
|
let pageIndex = 1;
|
|
188
186
|
let allRecordsFound = false;
|
|
187
|
+
const recordsPerPage = 5000;
|
|
189
188
|
while (!allRecordsFound) {
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
190
190
|
const response = await this.cloudflare.dnsRecords.browse(zoneId, {
|
|
191
191
|
page: pageIndex,
|
|
192
|
-
|
|
192
|
+
// eslint-disable-next-line camelcase
|
|
193
|
+
per_page: recordsPerPage,
|
|
193
194
|
});
|
|
194
195
|
records.push(...response.result);
|
|
195
|
-
allRecordsFound = response.result.length <
|
|
196
|
+
allRecordsFound = response.result.length < recordsPerPage;
|
|
196
197
|
pageIndex++;
|
|
197
198
|
}
|
|
198
199
|
return records;
|
|
@@ -216,8 +217,8 @@ class CloudflareClient {
|
|
|
216
217
|
return domains;
|
|
217
218
|
}
|
|
218
219
|
getDomainByRecordName(recordName) {
|
|
219
|
-
const parsedDomain =
|
|
220
|
-
if (parsedDomain.type !==
|
|
220
|
+
const parsedDomain = parseDomain(fromUrl(recordName));
|
|
221
|
+
if (parsedDomain.type !== ParseResultType.Listed || !parsedDomain.domain) {
|
|
221
222
|
throw new Error(`Could not parse domain. '${JSON.stringify(recordName)}' is not a valid record name.`);
|
|
222
223
|
}
|
|
223
224
|
let domain = '';
|
|
@@ -228,4 +229,3 @@ class CloudflareClient {
|
|
|
228
229
|
return domain.toLowerCase();
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
|
-
exports.default = CloudflareClient;
|
package/dist/lib/cron.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const node_cron_1 = __importDefault(require("node-cron"));
|
|
7
|
-
class Cron {
|
|
1
|
+
import cron from 'node-cron';
|
|
2
|
+
export default class Cron {
|
|
8
3
|
static createCronJob(cronExpression, callback) {
|
|
9
4
|
const cronExpressionIsInvalid = !this.isValid(cronExpression);
|
|
10
5
|
if (cronExpressionIsInvalid) {
|
|
11
6
|
// eslint-disable-next-line max-len
|
|
12
|
-
throw new Error(`'${cronExpression}' is not a valid cron expression.\nHere you can see how cron expressions work: https://cddnss.knaup.
|
|
7
|
+
throw new Error(`'${cronExpression}' is not a valid cron expression.\nHere you can see how cron expressions work: https://cddnss.knaup.pw/cron-expression-syntax`);
|
|
13
8
|
}
|
|
14
|
-
return
|
|
9
|
+
return cron.schedule(cronExpression, () => {
|
|
15
10
|
callback();
|
|
16
11
|
}, undefined);
|
|
17
12
|
}
|
|
18
13
|
static isValid(cronExpression) {
|
|
19
|
-
return
|
|
14
|
+
return cron.validate(cronExpression);
|
|
20
15
|
}
|
|
21
16
|
}
|
|
22
|
-
exports.default = Cron;
|
package/dist/lib/ip-utils.d.ts
CHANGED
package/dist/lib/ip-utils.js
CHANGED
|
@@ -1,36 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
-
}) : function(o, v) {
|
|
12
|
-
o["default"] = v;
|
|
13
|
-
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
-
if (mod && mod.__esModule) return mod;
|
|
16
|
-
var result = {};
|
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
-
__setModuleDefault(result, mod);
|
|
19
|
-
return result;
|
|
20
|
-
};
|
|
21
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
-
};
|
|
24
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
const wimIp = __importStar(require("what-is-my-ip-address"));
|
|
26
|
-
const public_ip_1 = __importDefault(require("public-ip"));
|
|
27
|
-
class IPUtils {
|
|
1
|
+
import * as wimIp from 'what-is-my-ip-address';
|
|
2
|
+
import { publicIpv4, publicIpv6 } from 'public-ip';
|
|
3
|
+
export default class IPUtils {
|
|
28
4
|
static ipPollingDelay = 10 * 1000;
|
|
29
5
|
static ipChangeEventListeners = new Map();
|
|
30
6
|
static async getIpv4() {
|
|
31
7
|
/* c8 ignore start*/
|
|
32
8
|
try {
|
|
33
|
-
return await
|
|
9
|
+
return await publicIpv4();
|
|
34
10
|
}
|
|
35
11
|
catch (error) {
|
|
36
12
|
return wimIp.v4();
|
|
@@ -40,7 +16,7 @@ class IPUtils {
|
|
|
40
16
|
static async getIpv6() {
|
|
41
17
|
/* c8 ignore start */
|
|
42
18
|
try {
|
|
43
|
-
return await
|
|
19
|
+
return await publicIpv6();
|
|
44
20
|
}
|
|
45
21
|
catch (error) {
|
|
46
22
|
return wimIp.v6();
|
|
@@ -48,7 +24,7 @@ class IPUtils {
|
|
|
48
24
|
/* c8 ignore stop*/
|
|
49
25
|
}
|
|
50
26
|
static async addIpChangeListener(callback) {
|
|
51
|
-
const eventListenerId = this.
|
|
27
|
+
const eventListenerId = this.getId();
|
|
52
28
|
let previousIp = await this.getIpv4();
|
|
53
29
|
/* c8 ignore start */
|
|
54
30
|
const intervalId = setInterval(async () => {
|
|
@@ -68,15 +44,9 @@ class IPUtils {
|
|
|
68
44
|
clearInterval(eventListenerIntervalId);
|
|
69
45
|
IPUtils.ipChangeEventListeners.delete(eventListenerId);
|
|
70
46
|
}
|
|
71
|
-
static
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
.toString(36);
|
|
76
|
-
const endingRandomString = Math.random().toString(36)
|
|
77
|
-
.substr(2);
|
|
78
|
-
const randomString = beginningRandomString + currentDateAsString + endingRandomString;
|
|
79
|
-
return randomString;
|
|
47
|
+
static getId() {
|
|
48
|
+
return Math.random().toString(36)
|
|
49
|
+
.substring(2, 15) + Math.random().toString(36)
|
|
50
|
+
.substring(2, 15);
|
|
80
51
|
}
|
|
81
52
|
}
|
|
82
|
-
exports.default = IPUtils;
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudflare-ddns-sync",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "A simple module to update DNS records on Cloudflare whenever you want",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Steffen Knaup <SteffenKnaup@hotmail.de>",
|
|
7
7
|
"license": "ISC",
|
|
8
|
+
"type": "module",
|
|
8
9
|
"keywords": [
|
|
9
10
|
"cloudflare",
|
|
10
11
|
"cddnss",
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"dyndns",
|
|
14
15
|
"sync"
|
|
15
16
|
],
|
|
16
|
-
"homepage": "https://cddnss.knaup.
|
|
17
|
+
"homepage": "https://cddnss.knaup.pw/",
|
|
17
18
|
"repository": {
|
|
18
19
|
"type": "git",
|
|
19
20
|
"url": "git://github.com:Steffen982/cloudflare-ddns-sync.git"
|
|
@@ -29,25 +30,25 @@
|
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
32
|
"cloudflare": "2.9.1",
|
|
32
|
-
"node-cron": "3.0.
|
|
33
|
-
"parse-domain": "
|
|
34
|
-
"public-ip": "
|
|
33
|
+
"node-cron": "3.0.2",
|
|
34
|
+
"parse-domain": "7.0.1",
|
|
35
|
+
"public-ip": "6.0.1",
|
|
35
36
|
"what-is-my-ip-address": "1.0.3"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@types/chai": "4.3.
|
|
39
|
+
"@types/chai": "4.3.4",
|
|
40
|
+
"@types/cloudflare": "^2.7.9",
|
|
39
41
|
"@types/minimist": "1.2.2",
|
|
40
|
-
"@types/mocha": "
|
|
41
|
-
"@types/node": "
|
|
42
|
-
"@types/node-cron": "3.0.
|
|
43
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
44
|
-
"@typescript-eslint/parser": "5.
|
|
45
|
-
"c8": "7.
|
|
46
|
-
"chai": "4.3.
|
|
47
|
-
"eslint": "8.
|
|
48
|
-
"minimist": "1.2.
|
|
49
|
-
"mocha": "
|
|
50
|
-
"
|
|
51
|
-
"typescript": "4.5.4"
|
|
42
|
+
"@types/mocha": "10.0.1",
|
|
43
|
+
"@types/node": "18.11.17",
|
|
44
|
+
"@types/node-cron": "3.0.6",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "5.46.1",
|
|
46
|
+
"@typescript-eslint/parser": "5.46.1",
|
|
47
|
+
"c8": "7.12.0",
|
|
48
|
+
"chai": "4.3.7",
|
|
49
|
+
"eslint": "8.30.0",
|
|
50
|
+
"minimist": "1.2.7",
|
|
51
|
+
"mocha": "10.2.0",
|
|
52
|
+
"typescript": "4.9.4"
|
|
52
53
|
}
|
|
53
54
|
}
|