@nictool/dns-resource-record 1.1.7 → 1.2.1
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 +26 -43
- package/README.md +48 -48
- package/index.js +83 -29
- package/lib/tinydns.js +68 -61
- package/package.json +1 -2
- package/rr/a.js +32 -23
- package/rr/aaaa.js +49 -35
- package/rr/caa.js +56 -44
- package/rr/cert.js +21 -19
- package/rr/cname.js +22 -23
- package/rr/dname.js +23 -23
- package/rr/dnskey.js +45 -43
- package/rr/ds.js +40 -40
- package/rr/hinfo.js +29 -28
- package/rr/https.js +62 -0
- package/rr/ipseckey.js +69 -50
- package/rr/key.js +23 -23
- package/rr/loc.js +71 -58
- package/rr/mx.js +41 -27
- package/rr/naptr.js +52 -53
- package/rr/ns.js +26 -23
- package/rr/nsec.js +24 -20
- package/rr/nsec3.js +59 -46
- package/rr/nsec3param.js +24 -26
- package/rr/nxt.js +65 -0
- package/rr/openpgpkey.js +18 -15
- package/rr/ptr.js +20 -21
- package/rr/rrsig.js +28 -23
- package/rr/sig.js +25 -20
- package/rr/smimea.js +36 -31
- package/rr/soa.js +56 -42
- package/rr/spf.js +21 -18
- package/rr/srv.js +45 -45
- package/rr/sshfp.js +30 -31
- package/rr/svcb.js +64 -0
- package/rr/tlsa.js +50 -45
- package/rr/tsig.js +56 -0
- package/rr/txt.js +42 -35
- package/rr/uri.js +33 -33
- package/rr/wks.js +45 -0
- package/rr.js +133 -87
- package/.codeclimate.yml +0 -25
- package/DEVELOP.md +0 -23
- package/test/a.js +0 -76
- package/test/aaaa.js +0 -79
- package/test/base.js +0 -138
- package/test/caa.js +0 -104
- package/test/cert.js +0 -48
- package/test/cname.js +0 -41
- package/test/dname.js +0 -53
- package/test/dnskey.js +0 -44
- package/test/ds.js +0 -44
- package/test/fake.js +0 -26
- package/test/hinfo.js +0 -75
- package/test/ipseckey.js +0 -115
- package/test/key.js +0 -37
- package/test/loc.js +0 -71
- package/test/mx.js +0 -75
- package/test/naptr.js +0 -40
- package/test/ns.js +0 -53
- package/test/nsec.js +0 -38
- package/test/nsec3.js +0 -40
- package/test/nsec3param.js +0 -26
- package/test/openpgpkey.js +0 -35
- package/test/ptr.js +0 -54
- package/test/rr.js +0 -196
- package/test/smimea.js +0 -45
- package/test/soa.js +0 -77
- package/test/spf.js +0 -48
- package/test/srv.js +0 -81
- package/test/sshfp.js +0 -62
- package/test/tinydns.js +0 -140
- package/test/tlsa.js +0 -54
- package/test/txt.js +0 -70
- package/test/uri.js +0 -61
package/rr.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import util from 'node:util'
|
|
1
2
|
|
|
2
3
|
export default class RR extends Map {
|
|
3
|
-
constructor
|
|
4
|
+
constructor(opts) {
|
|
4
5
|
super()
|
|
5
6
|
|
|
6
7
|
if (opts === null) return
|
|
@@ -15,44 +16,48 @@ export default class RR extends Map {
|
|
|
15
16
|
this.setTimestamp(opts?.timestamp)
|
|
16
17
|
|
|
17
18
|
this.setOwner(opts?.owner)
|
|
18
|
-
this.setType
|
|
19
|
-
this.setTtl
|
|
19
|
+
this.setType(opts?.type)
|
|
20
|
+
this.setTtl(opts?.ttl)
|
|
20
21
|
this.setClass(opts?.class)
|
|
21
22
|
|
|
22
23
|
for (const f of this.getFields('rdata')) {
|
|
23
24
|
const fnName = `set${this.ucfirst(f)}`
|
|
24
|
-
if (this[fnName] === undefined)
|
|
25
|
+
if (this[fnName] === undefined)
|
|
26
|
+
this.throwHelp(`Missing ${fnName} in class ${this.get('type')}`)
|
|
25
27
|
this[fnName](opts[f])
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
if (opts.comment) this.set('comment', opts.comment)
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
ucfirst
|
|
32
|
-
return str
|
|
33
|
+
ucfirst(str) {
|
|
34
|
+
return str
|
|
35
|
+
.split(/\s/)
|
|
36
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
37
|
+
.join('')
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
setClass
|
|
40
|
+
setClass(c) {
|
|
36
41
|
switch (c) {
|
|
37
|
-
case 'IN':
|
|
42
|
+
case 'IN': // 1
|
|
38
43
|
case undefined:
|
|
39
44
|
case null:
|
|
40
45
|
case '':
|
|
41
46
|
this.set('class', 'IN')
|
|
42
47
|
break
|
|
43
|
-
case 'CS':
|
|
44
|
-
case 'CH':
|
|
45
|
-
case 'HS':
|
|
46
|
-
case 'NONE':
|
|
47
|
-
case 'ANY':
|
|
48
|
+
case 'CS': // 2
|
|
49
|
+
case 'CH': // 3
|
|
50
|
+
case 'HS': // 4
|
|
51
|
+
case 'NONE': // 254
|
|
52
|
+
case 'ANY': // 255
|
|
48
53
|
this.set('class', c)
|
|
49
54
|
break
|
|
50
55
|
default:
|
|
51
|
-
|
|
56
|
+
this.throwHelp(`invalid class ${c}`)
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
setLocation
|
|
60
|
+
setLocation(l) {
|
|
56
61
|
switch (l) {
|
|
57
62
|
case undefined:
|
|
58
63
|
return
|
|
@@ -61,7 +66,7 @@ export default class RR extends Map {
|
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
setTimestamp
|
|
69
|
+
setTimestamp(l) {
|
|
65
70
|
switch (l) {
|
|
66
71
|
case undefined:
|
|
67
72
|
return
|
|
@@ -70,32 +75,35 @@ export default class RR extends Map {
|
|
|
70
75
|
}
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
setOwner
|
|
74
|
-
if (n === undefined)
|
|
78
|
+
setOwner(n) {
|
|
79
|
+
if (n === undefined) this.throwHelp(`owner is required`)
|
|
75
80
|
|
|
76
81
|
if (n.length < 1 || n.length > 255)
|
|
77
|
-
|
|
82
|
+
this.throwHelp(
|
|
83
|
+
'Domain names must have 1-255 octets (characters): RFC 2181',
|
|
84
|
+
)
|
|
78
85
|
|
|
79
|
-
this.isFullyQualified(
|
|
86
|
+
this.isFullyQualified(this.constructor.name, 'owner', n)
|
|
80
87
|
this.hasValidLabels(n)
|
|
81
88
|
|
|
82
89
|
// wildcard records: RFC 1034, 4592
|
|
83
90
|
if (/\*/.test(n)) {
|
|
84
|
-
if (!/^\*\./.test(n) && !/\.\*\./.test(n))
|
|
91
|
+
if (!/^\*\./.test(n) && !/\.\*\./.test(n))
|
|
92
|
+
this.throwHelp('only *.something or * (by itself) is a valid wildcard')
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
this.set('owner', n.toLowerCase())
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
setTtl
|
|
91
|
-
|
|
98
|
+
setTtl(t) {
|
|
92
99
|
if (t === undefined) t = this?.default?.ttl
|
|
93
100
|
if (t === undefined) {
|
|
94
|
-
if ([
|
|
95
|
-
|
|
101
|
+
if (['SOA', 'SSHPF'].includes(this.get('type'))) return
|
|
102
|
+
this.throwHelp('TTL is required, no default available')
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
if (typeof t !== 'number')
|
|
105
|
+
if (typeof t !== 'number')
|
|
106
|
+
this.throwHelp(`TTL must be numeric (${typeof t})`)
|
|
99
107
|
|
|
100
108
|
// RFC 1035, 2181
|
|
101
109
|
this.is32bitInt(this.owner, 'TTL', t)
|
|
@@ -103,24 +111,34 @@ export default class RR extends Map {
|
|
|
103
111
|
this.set('ttl', t)
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
setType
|
|
114
|
+
setType(t) {
|
|
107
115
|
switch (t) {
|
|
108
116
|
case '':
|
|
109
117
|
case undefined:
|
|
110
|
-
|
|
118
|
+
this.throwHelp(`type is required`)
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
if (t.toUpperCase() !== this.constructor.name)
|
|
114
|
-
|
|
122
|
+
this.throwHelp(`type ${t} doesn't match ${this.constructor.name}`)
|
|
115
123
|
|
|
116
124
|
this.set('type', t.toUpperCase())
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
throwHelp(e) {
|
|
128
|
+
if (this.constructor.name === 'RR') throw new Error(e)
|
|
129
|
+
|
|
130
|
+
const example = this.getCanonical
|
|
131
|
+
? `Example ${this.constructor.name}:\n${util.inspect(this.getCanonical(), { depth: null })}\n\n`
|
|
132
|
+
: `${this.constructor.name} records have the fields: ${this.getFields().join(', ')}\n\n`
|
|
133
|
+
|
|
134
|
+
throw new Error(`${e}\n\n${example}${this.citeRFC()}\n`)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
citeRFC() {
|
|
138
|
+
return `see RFC${this.getRFCs().length > 1 ? 's' : ''} ${this.getRFCs()}`
|
|
121
139
|
}
|
|
122
140
|
|
|
123
|
-
fullyQualify
|
|
141
|
+
fullyQualify(hostname, origin) {
|
|
124
142
|
if (!hostname) return hostname
|
|
125
143
|
if (hostname === '@' && origin) hostname = origin
|
|
126
144
|
if (hostname.endsWith('.')) return hostname.toLowerCase()
|
|
@@ -128,7 +146,7 @@ export default class RR extends Map {
|
|
|
128
146
|
return `${hostname}.`
|
|
129
147
|
}
|
|
130
148
|
|
|
131
|
-
getPrefix
|
|
149
|
+
getPrefix(zone_opts = {}) {
|
|
132
150
|
const classVal = zone_opts.hide?.class ? '' : this.get('class')
|
|
133
151
|
|
|
134
152
|
let rrTTL = this.get('ttl')
|
|
@@ -137,25 +155,24 @@ export default class RR extends Map {
|
|
|
137
155
|
let owner = this.get('owner')
|
|
138
156
|
if (zone_opts.hide?.sameOwner && zone_opts.previousOwner === owner) {
|
|
139
157
|
owner = ''
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
158
|
+
} else {
|
|
142
159
|
owner = this.getFQDN('owner', zone_opts)
|
|
143
160
|
}
|
|
144
161
|
|
|
145
162
|
return `${owner}\t${rrTTL}\t${classVal}\t${this.get('type')}`
|
|
146
163
|
}
|
|
147
164
|
|
|
148
|
-
getEmpty
|
|
165
|
+
getEmpty(prop) {
|
|
149
166
|
return this.get(prop) === undefined ? '' : this.get(prop)
|
|
150
167
|
}
|
|
151
168
|
|
|
152
|
-
getComment
|
|
169
|
+
getComment(prop) {
|
|
153
170
|
const c = this.get('comment')
|
|
154
171
|
if (!c || !c[prop]) return ''
|
|
155
172
|
return c[prop]
|
|
156
173
|
}
|
|
157
174
|
|
|
158
|
-
getQuoted
|
|
175
|
+
getQuoted(prop) {
|
|
159
176
|
// if prop is not in quoted list, return bare
|
|
160
177
|
if (!this.getQuotedFields().includes(prop)) return this.get(prop)
|
|
161
178
|
|
|
@@ -165,16 +182,16 @@ export default class RR extends Map {
|
|
|
165
182
|
return `"${this.get(prop)}"` // add double quotes
|
|
166
183
|
}
|
|
167
184
|
|
|
168
|
-
getQuotedFields
|
|
185
|
+
getQuotedFields() {
|
|
169
186
|
return []
|
|
170
187
|
}
|
|
171
188
|
|
|
172
|
-
getRdataFields
|
|
189
|
+
getRdataFields() {
|
|
173
190
|
return []
|
|
174
191
|
}
|
|
175
192
|
|
|
176
|
-
getFields
|
|
177
|
-
const commonFields = [
|
|
193
|
+
getFields(arg) {
|
|
194
|
+
const commonFields = ['owner', 'ttl', 'class', 'type']
|
|
178
195
|
Object.freeze(commonFields)
|
|
179
196
|
|
|
180
197
|
switch (arg) {
|
|
@@ -187,23 +204,24 @@ export default class RR extends Map {
|
|
|
187
204
|
}
|
|
188
205
|
}
|
|
189
206
|
|
|
190
|
-
getFQDN
|
|
207
|
+
getFQDN(field, zone_opts = {}) {
|
|
191
208
|
let fqdn = this.get(field)
|
|
192
|
-
if (!fqdn)
|
|
209
|
+
if (!fqdn) this.throwHelp(`empty value for field ${field}`)
|
|
193
210
|
if (!fqdn.endsWith('.')) fqdn += '.'
|
|
194
211
|
|
|
195
212
|
if (zone_opts.hide?.origin && zone_opts.origin) {
|
|
196
213
|
if (fqdn === zone_opts.origin) return '@'
|
|
197
|
-
if (fqdn.endsWith(zone_opts.origin))
|
|
214
|
+
if (fqdn.endsWith(zone_opts.origin))
|
|
215
|
+
return fqdn.slice(0, fqdn.length - zone_opts.origin.length - 1)
|
|
198
216
|
}
|
|
199
217
|
|
|
200
218
|
return fqdn
|
|
201
219
|
}
|
|
202
220
|
|
|
203
|
-
getTinyFQDN
|
|
221
|
+
getTinyFQDN(field) {
|
|
204
222
|
const val = this.get(field)
|
|
205
|
-
if (val === '') return val
|
|
206
|
-
if (val === '.') return val
|
|
223
|
+
if (val === '') return val // empty
|
|
224
|
+
if (val === '.') return val // null MX
|
|
207
225
|
|
|
208
226
|
// strip off trailing ., tinydns doesn't require it for FQDN
|
|
209
227
|
if (val.endsWith('.')) return val.slice(0, -1)
|
|
@@ -211,15 +229,17 @@ export default class RR extends Map {
|
|
|
211
229
|
return val
|
|
212
230
|
}
|
|
213
231
|
|
|
214
|
-
getTinydnsGeneric
|
|
232
|
+
getTinydnsGeneric(rdata) {
|
|
215
233
|
return `:${this.getTinyFQDN('owner')}:${this.getTypeId()}:${rdata}:${this.getTinydnsPostamble()}\n`
|
|
216
234
|
}
|
|
217
235
|
|
|
218
|
-
getTinydnsPostamble
|
|
219
|
-
return [
|
|
236
|
+
getTinydnsPostamble() {
|
|
237
|
+
return ['ttl', 'timestamp', 'location']
|
|
238
|
+
.map((f) => this.getEmpty(f))
|
|
239
|
+
.join(':')
|
|
220
240
|
}
|
|
221
241
|
|
|
222
|
-
hasValidLabels
|
|
242
|
+
hasValidLabels(hostname) {
|
|
223
243
|
// RFC 952 defined valid hostnames
|
|
224
244
|
// RFC 1035 limited domain label chars to letters, digits, and hyphen
|
|
225
245
|
// RFC 1123 allowed hostnames to start with a digit
|
|
@@ -227,68 +247,94 @@ export default class RR extends Map {
|
|
|
227
247
|
const fq = hostname.endsWith('.') ? hostname.slice(0, -1) : hostname
|
|
228
248
|
for (const label of fq.split('.')) {
|
|
229
249
|
if (label.length < 1 || label.length > 63)
|
|
230
|
-
|
|
250
|
+
this.throwHelp('Labels must have 1-63 octets (characters), RFC 2181')
|
|
231
251
|
}
|
|
232
252
|
}
|
|
233
253
|
|
|
234
|
-
is8bitInt
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
254
|
+
is8bitInt(type, field, value) {
|
|
255
|
+
if (
|
|
256
|
+
typeof value === 'number' &&
|
|
257
|
+
parseInt(value, 10) === value && // assure integer
|
|
258
|
+
value >= 0 &&
|
|
259
|
+
value <= 255
|
|
260
|
+
)
|
|
261
|
+
return true
|
|
262
|
+
|
|
263
|
+
this.throwHelp(
|
|
264
|
+
`${type} ${field} must be a 8-bit integer (in the range 0-255)`,
|
|
265
|
+
)
|
|
241
266
|
}
|
|
242
267
|
|
|
243
|
-
is16bitInt
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
268
|
+
is16bitInt(type, field, value) {
|
|
269
|
+
if (
|
|
270
|
+
typeof value === 'number' &&
|
|
271
|
+
parseInt(value, 10) === value && // assure integer
|
|
272
|
+
value >= 0 &&
|
|
273
|
+
value <= 65535
|
|
274
|
+
)
|
|
275
|
+
return true
|
|
276
|
+
|
|
277
|
+
this.throwHelp(
|
|
278
|
+
`${type} ${field} must be a 16-bit integer (in the range 0-65535)`,
|
|
279
|
+
)
|
|
250
280
|
}
|
|
251
281
|
|
|
252
|
-
is32bitInt
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
282
|
+
is32bitInt(type, field, value) {
|
|
283
|
+
if (
|
|
284
|
+
typeof value === 'number' &&
|
|
285
|
+
parseInt(value, 10) === value && // assure integer
|
|
286
|
+
value >= 0 &&
|
|
287
|
+
value <= 2147483647
|
|
288
|
+
)
|
|
289
|
+
return true
|
|
290
|
+
|
|
291
|
+
this.throwHelp(
|
|
292
|
+
`${type} ${field} must be a 32-bit integer (in the range 0-2147483647)`,
|
|
293
|
+
)
|
|
259
294
|
}
|
|
260
295
|
|
|
261
|
-
isQuoted
|
|
296
|
+
isQuoted(val) {
|
|
262
297
|
return /^["']/.test(val) && /["']$/.test(val)
|
|
263
298
|
}
|
|
264
299
|
|
|
265
|
-
isFullyQualified
|
|
300
|
+
isFullyQualified(type, field, hostname) {
|
|
266
301
|
if (hostname.endsWith('.')) return true
|
|
267
302
|
|
|
268
|
-
|
|
303
|
+
this.throwHelp(`${type}: ${field} must be fully qualified`)
|
|
269
304
|
}
|
|
270
305
|
|
|
271
|
-
isValidHostname
|
|
306
|
+
isValidHostname(type, field, hostname) {
|
|
272
307
|
const allowed = new RegExp(/[^a-zA-Z0-9\-._/\\]/)
|
|
273
308
|
if (!allowed.test(hostname)) return true
|
|
274
309
|
|
|
275
310
|
const matches = allowed.exec(hostname)
|
|
276
|
-
|
|
311
|
+
this.throwHelp(
|
|
312
|
+
`${type}, ${field} has invalid hostname character (${matches[0]})`,
|
|
313
|
+
)
|
|
277
314
|
}
|
|
278
315
|
|
|
279
|
-
toBind
|
|
280
|
-
return `${this.getPrefix(zone_opts)}\t${this.getRdataFields()
|
|
316
|
+
toBind(zone_opts) {
|
|
317
|
+
return `${this.getPrefix(zone_opts)}\t${this.getRdataFields()
|
|
318
|
+
.map((f) => this.getQuoted(f))
|
|
319
|
+
.join('\t')}\n`
|
|
281
320
|
}
|
|
282
321
|
|
|
283
|
-
toMaraDNS
|
|
322
|
+
toMaraDNS() {
|
|
284
323
|
const type = this.get('type')
|
|
285
|
-
const supportedTypes =
|
|
324
|
+
const supportedTypes =
|
|
325
|
+
'A PTR MX AAAA SRV NAPTR NS SOA TXT SPF RAW FQDN4 FQDN6 CNAME HINFO WKS LOC'.split(
|
|
326
|
+
/\s+/g,
|
|
327
|
+
)
|
|
286
328
|
if (!supportedTypes.includes(type)) return this.toMaraGeneric()
|
|
287
|
-
return `${this.get('owner')}\t+${this.get('ttl')}\t${type}\t${this.getRdataFields()
|
|
329
|
+
return `${this.get('owner')}\t+${this.get('ttl')}\t${type}\t${this.getRdataFields()
|
|
330
|
+
.map((f) => this.getQuoted(f))
|
|
331
|
+
.join('\t')} ~\n`
|
|
288
332
|
}
|
|
289
333
|
|
|
290
|
-
toMaraGeneric
|
|
291
|
-
//
|
|
292
|
-
return `${this.get('owner')}\t+${this.get('ttl')}\tRAW ${this.getTypeId()}\t'${this.getRdataFields()
|
|
334
|
+
toMaraGeneric() {
|
|
335
|
+
// this.throwHelp(`\nMaraDNS does not support ${type} records yet and this package does not support MaraDNS generic records. Yet.\n`)
|
|
336
|
+
return `${this.get('owner')}\t+${this.get('ttl')}\tRAW ${this.getTypeId()}\t'${this.getRdataFields()
|
|
337
|
+
.map((f) => this.getQuoted(f))
|
|
338
|
+
.join(' ')}' ~\n`
|
|
293
339
|
}
|
|
294
340
|
}
|
package/.codeclimate.yml
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
checks:
|
|
2
|
-
return-statements:
|
|
3
|
-
enabled: false
|
|
4
|
-
similar-code:
|
|
5
|
-
enabled: false
|
|
6
|
-
file-lines:
|
|
7
|
-
config:
|
|
8
|
-
threshold: 500
|
|
9
|
-
method-lines:
|
|
10
|
-
config:
|
|
11
|
-
threshold: 50
|
|
12
|
-
method-complexity:
|
|
13
|
-
config:
|
|
14
|
-
threshold: 10
|
|
15
|
-
|
|
16
|
-
plugins:
|
|
17
|
-
eslint:
|
|
18
|
-
enabled: true
|
|
19
|
-
channel: "eslint-8"
|
|
20
|
-
config:
|
|
21
|
-
config: ".eslintrc.yaml"
|
|
22
|
-
|
|
23
|
-
ratings:
|
|
24
|
-
paths:
|
|
25
|
-
- "**.js"
|
package/DEVELOP.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# Release process
|
|
3
|
-
|
|
4
|
-
In your local repo:
|
|
5
|
-
|
|
6
|
-
- make your changes
|
|
7
|
-
- git add .
|
|
8
|
-
- `.release/do.sh` {major|minor|patch}
|
|
9
|
-
- fill in the blanks in CHANGELOG.md
|
|
10
|
-
- `.release/push.sh`
|
|
11
|
-
|
|
12
|
-
Upon merge to `master`:
|
|
13
|
-
|
|
14
|
-
- the new version will be published to NPM.
|
|
15
|
-
- a GitHub release will be published.
|
|
16
|
-
- a release tag will be committed to the repo.
|
|
17
|
-
|
|
18
|
-
## Clean
|
|
19
|
-
|
|
20
|
-
`.release/cleanup.sh`
|
|
21
|
-
|
|
22
|
-
- will switch to the master branch
|
|
23
|
-
- delete the release branch
|
package/test/a.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import A from '../rr/a.js'
|
|
3
|
-
import * as base from './base.js'
|
|
4
|
-
|
|
5
|
-
const defaults = { class: 'IN', ttl: 3600, type: 'A', address: '192.0.2.127' }
|
|
6
|
-
|
|
7
|
-
const validRecords = [
|
|
8
|
-
{
|
|
9
|
-
...defaults,
|
|
10
|
-
owner: 'test.example.com.',
|
|
11
|
-
testB: 'test.example.com.\t3600\tIN\tA\t192.0.2.127\n',
|
|
12
|
-
testT: '+test.example.com:192.0.2.127:3600::\n',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
...defaults,
|
|
16
|
-
owner: 'test.example.com.',
|
|
17
|
-
ttl : 2147483647,
|
|
18
|
-
testB: 'test.example.com.\t2147483647\tIN\tA\t192.0.2.127\n',
|
|
19
|
-
testT: '+test.example.com:192.0.2.127:2147483647::\n',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
...defaults,
|
|
23
|
-
owner: 'a.',
|
|
24
|
-
ttl : 86400,
|
|
25
|
-
testB: 'a.\t86400\tIN\tA\t192.0.2.127\n',
|
|
26
|
-
testT: '+a:192.0.2.127:86400::\n',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
...defaults,
|
|
30
|
-
owner: '*.example.com.',
|
|
31
|
-
testB: '*.example.com.\t3600\tIN\tA\t192.0.2.127\n',
|
|
32
|
-
testT: '+*.example.com:192.0.2.127:3600::\n',
|
|
33
|
-
},
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
const invalidRecords = [
|
|
37
|
-
{ ...defaults, owner: '', msg: /RFC/ },
|
|
38
|
-
{ ...defaults, owner: 'something*', msg: /fully/ },
|
|
39
|
-
{ ...defaults, owner: 'some*thing', msg: /fully/ },
|
|
40
|
-
{ ...defaults, owner: '*something', msg: /fully/ },
|
|
41
|
-
{ ...defaults, owner: 'something.*', msg: /fully/ },
|
|
42
|
-
{ ...defaults, address: 'hosts.not.valid.here', msg: /address must be IPv4/ },
|
|
43
|
-
{ ...defaults, address: '', msg: /address is required/ },
|
|
44
|
-
{ ...defaults, address: undefined, msg: /address is required/ },
|
|
45
|
-
{ ...defaults, address: '1.x.2.3', msg: /address must be IPv4/ },
|
|
46
|
-
{ ...defaults, address: '.1.2.3', msg: /address must be IPv4/ },
|
|
47
|
-
{ ...defaults, type: '', msg: /type is required/ },
|
|
48
|
-
{ ...defaults, type: undefined, msg: /type is required/ },
|
|
49
|
-
{ ...defaults, ttl: '', msg: /TTL must be numeric/ },
|
|
50
|
-
{ ...defaults, ttl: -299, msg: /TTL must be a 32-bit integer/ },
|
|
51
|
-
{ ...defaults, ttl: 2147483648, msg: /TTL must be a 32-bit integer/ },
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
// copy invalid properties to a valid object
|
|
55
|
-
for (let i = 0; i < invalidRecords.length; i++) {
|
|
56
|
-
const temp = JSON.parse(JSON.stringify(validRecords[0]))
|
|
57
|
-
Object.assign(temp, invalidRecords[i])
|
|
58
|
-
invalidRecords[i] = temp
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
describe('A record', function () {
|
|
62
|
-
base.valid(A, validRecords)
|
|
63
|
-
base.invalid(A, invalidRecords)
|
|
64
|
-
|
|
65
|
-
base.getDescription(A)
|
|
66
|
-
base.getRFCs(A, validRecords[0])
|
|
67
|
-
base.getRdataFields(A, [ 'address' ])
|
|
68
|
-
base.getFields(A, [ 'address' ])
|
|
69
|
-
base.getTypeId(A, 1)
|
|
70
|
-
|
|
71
|
-
base.toBind(A, validRecords)
|
|
72
|
-
base.toTinydns(A, validRecords)
|
|
73
|
-
|
|
74
|
-
base.fromBind(A, validRecords)
|
|
75
|
-
base.fromTinydns(A, validRecords)
|
|
76
|
-
})
|
package/test/aaaa.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import assert from 'assert'
|
|
3
|
-
|
|
4
|
-
import * as base from './base.js'
|
|
5
|
-
import AAAA from '../rr/aaaa.js'
|
|
6
|
-
|
|
7
|
-
const defaults = { class: 'IN', ttl: 3600, type: 'AAAA' }
|
|
8
|
-
|
|
9
|
-
const validRecords = [
|
|
10
|
-
{
|
|
11
|
-
...defaults,
|
|
12
|
-
owner : 'test.example.com.',
|
|
13
|
-
address: '2001:0db8:0020:000a:0000:0000:0000:0004',
|
|
14
|
-
testB : 'test.example.com.\t3600\tIN\tAAAA\t2001:db8:20:a::4\n',
|
|
15
|
-
testT : ':test.example.com:28:\\040\\001\\015\\270\\000\\040\\000\\012\\000\\000\\000\\000\\000\\000\\000\\004:3600::\n',
|
|
16
|
-
},
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
const invalidRecords = [
|
|
20
|
-
{
|
|
21
|
-
...defaults,
|
|
22
|
-
owner : 'test.example.com.',
|
|
23
|
-
address: '192.0.2.204',
|
|
24
|
-
msg : /address must be IPv6/,
|
|
25
|
-
},
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
describe('AAAA record', function () {
|
|
29
|
-
base.valid(AAAA, validRecords)
|
|
30
|
-
base.invalid(AAAA, invalidRecords)
|
|
31
|
-
|
|
32
|
-
base.getDescription(AAAA)
|
|
33
|
-
base.getRFCs(AAAA, validRecords[0])
|
|
34
|
-
base.getFields(AAAA, [ 'address' ])
|
|
35
|
-
base.getTypeId(AAAA, 28)
|
|
36
|
-
|
|
37
|
-
base.toBind(AAAA, validRecords)
|
|
38
|
-
base.toTinydns(AAAA, validRecords)
|
|
39
|
-
|
|
40
|
-
base.fromBind(AAAA, validRecords)
|
|
41
|
-
base.fromTinydns(AAAA, validRecords)
|
|
42
|
-
|
|
43
|
-
for (const val of validRecords) {
|
|
44
|
-
it(`imports tinydns AAAA (generic) record (${val.owner})`, async function () {
|
|
45
|
-
const r = new AAAA({ tinyline: val.testT })
|
|
46
|
-
if (process.env.DEBUG) console.dir(r)
|
|
47
|
-
for (const f of [ 'owner', 'address', 'ttl' ]) {
|
|
48
|
-
assert.deepStrictEqual(r.get(f), val[f], `${f}: ${r.get(f)} !== ${val[f]}`)
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const tests = [
|
|
54
|
-
{ e: '2001:0db8:0020:000a:0000:0000:0000:0004', c: '2001:db8:20:a::4' },
|
|
55
|
-
{ e: '0000:0000:0000:0000:0000:0000:0000:0000', c: '::' },
|
|
56
|
-
{ e: '0000:0000:0000:0000:0000:0000:0000:0001', c: '::1' },
|
|
57
|
-
{ e: '2001:0db8:0000:0000:0000:0000:0002:0001', c: '2001:db8::2:1' },
|
|
58
|
-
{ e: '2001:0db8:0000:0001:0001:0001:0001:0001', c: '2001:db8:0:1:1:1:1:1' },
|
|
59
|
-
{ e: '2001:0DB8:0000:0000:0008:0800:200C:417A', c: '2001:DB8::8:800:200C:417A' },
|
|
60
|
-
]
|
|
61
|
-
|
|
62
|
-
describe('compress', function () {
|
|
63
|
-
const r = new AAAA(null)
|
|
64
|
-
for (const t of tests) {
|
|
65
|
-
it(`compresses IPv6 address (${t.e})`, function () {
|
|
66
|
-
assert.equal(r.compress(t.e), t.c)
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
describe('expand', function () {
|
|
72
|
-
const r = new AAAA(null)
|
|
73
|
-
for (const t of tests) {
|
|
74
|
-
it(`expands IPv6 address (${t.c})`, function () {
|
|
75
|
-
assert.equal(r.expand(t.c), t.e)
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
})
|