-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathNetcupUpdater.ts
133 lines (120 loc) · 3.45 KB
/
NetcupUpdater.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { UpdateConfig, Updater } from "./Updater.interface";
import NetcupApi, {
DnsRecord,
InfoDNSRecordsResponseData,
InfoDNSZoneResponseData,
} from "netcup-node";
import { assertEnvironment, getEnv } from "../EnvironmentReader.js";
type ARecord = "A";
type AAAARecord = "AAAA";
type RecordType = ARecord | AAAARecord;
/**
* An Updater to set the current IP addresses via
* the Netcup DNS API.
*
* Configuration (environment variables):
* - `NETCUP_CUSTOMER_NUMBER`
* - `NETCUP_API_PASSWORD`
* - `NETCUP_API_KEY`
*
* All environment variables can be read from a file.
* The main purpose is to support docker secrets.
* For this to work just add `_FILE` suffix.
* (E.g. `NETCUP_API_PASSWORD` -> `NETCUP_API_PASSWORD_FILE`)
*/
export class NetcupUpdater implements Updater {
public init(): void {
assertEnvironment("NETCUP_CUSTOMER_NUMBER");
assertEnvironment("NETCUP_API_PASSWORD");
assertEnvironment("NETCUP_API_KEY");
}
/**
* Set IPv4 and/or IPv6 address for "hostname"."domain"
*
* @param updateConfig - An object providing the `domain`, a `hostname` describing
* the record, an `ip4addr` (optional) and/or an `ip6addr`
* (optional) to update
*
* @returns The update result message
*/
public async update({
domain,
hostname,
ip4addr,
ip6addr,
}: UpdateConfig): Promise<any> {
// not in init because session might expire between update calls
const api = await new NetcupApi().init({
apikey: getEnv("NETCUP_API_KEY"),
apipassword: getEnv("NETCUP_API_PASSWORD"),
customernumber: getEnv("NETCUP_CUSTOMER_NUMBER"),
});
const { responsedata: dnsrecordset } = await api.infoDnsRecords({
domainname: domain,
});
if (ip4addr) {
this.setIp4Addr(dnsrecordset, hostname, ip4addr);
}
if (ip6addr) {
this.setIp6Addr(dnsrecordset, hostname, ip6addr);
}
const updateResult = await api.updateDnsRecords({
domainname: domain,
dnsrecordset,
});
return updateResult.longmessage;
}
private setIp4Addr(
dnsrecordset: InfoDNSRecordsResponseData,
hostname: string,
ipAddr: string
): void {
const ARecord: ARecord = "A";
return this.setIpAddr(dnsrecordset, ARecord, hostname, ipAddr);
}
private setIp6Addr(
dnsrecordset: InfoDNSRecordsResponseData,
hostname: string,
ipAddr: string
): void {
const AAAARecord: AAAARecord = "AAAA";
return this.setIpAddr(dnsrecordset, AAAARecord, hostname, ipAddr);
}
private setIpAddr(
dnsrecordset: InfoDNSRecordsResponseData,
type: RecordType,
hostname: string,
ipAddr: string
): void {
if (this.hasRecordForHost(dnsrecordset.dnsrecords, type, hostname)) {
const recordIndex = this.getRecordIndex(
dnsrecordset.dnsrecords,
type,
hostname
);
dnsrecordset.dnsrecords[recordIndex].destination = ipAddr;
} else {
dnsrecordset.dnsrecords.push({
destination: ipAddr,
hostname,
type,
});
}
}
private getRecordIndex(
dnsRecords: DnsRecord[],
type: RecordType,
hostname: string
): number {
return dnsRecords.findIndex(
(entry) => entry.hostname === hostname && entry.type === type
);
}
private hasRecordForHost(
dnsRecords: DnsRecord[],
type: RecordType,
hostname: string
): boolean {
return this.getRecordIndex(dnsRecords, type, hostname) !== -1;
}
}