@nictool/dns-resource-record 1.1.3

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 (71) hide show
  1. package/.codeclimate.yml +25 -0
  2. package/CHANGELOG.md +253 -0
  3. package/DEVELOP.md +23 -0
  4. package/LICENSE +29 -0
  5. package/README.md +267 -0
  6. package/index.js +67 -0
  7. package/lib/tinydns.js +186 -0
  8. package/package.json +40 -0
  9. package/rr/a.js +65 -0
  10. package/rr/aaaa.js +137 -0
  11. package/rr/caa.js +129 -0
  12. package/rr/cert.js +75 -0
  13. package/rr/cname.js +76 -0
  14. package/rr/dname.js +74 -0
  15. package/rr/dnskey.js +117 -0
  16. package/rr/ds.js +104 -0
  17. package/rr/hinfo.js +84 -0
  18. package/rr/ipseckey.js +159 -0
  19. package/rr/key.js +73 -0
  20. package/rr/loc.js +216 -0
  21. package/rr/mx.js +86 -0
  22. package/rr/naptr.js +146 -0
  23. package/rr/ns.js +74 -0
  24. package/rr/nsec.js +61 -0
  25. package/rr/nsec3.js +99 -0
  26. package/rr/nsec3param.js +84 -0
  27. package/rr/openpgpkey.js +44 -0
  28. package/rr/ptr.js +65 -0
  29. package/rr/rrsig.js +101 -0
  30. package/rr/sig.js +100 -0
  31. package/rr/smimea.js +73 -0
  32. package/rr/soa.js +140 -0
  33. package/rr/spf.js +54 -0
  34. package/rr/srv.js +122 -0
  35. package/rr/sshfp.js +86 -0
  36. package/rr/tlsa.js +106 -0
  37. package/rr/txt.js +122 -0
  38. package/rr/uri.js +95 -0
  39. package/rr.js +291 -0
  40. package/test/a.js +76 -0
  41. package/test/aaaa.js +79 -0
  42. package/test/base.js +138 -0
  43. package/test/caa.js +104 -0
  44. package/test/cert.js +48 -0
  45. package/test/cname.js +41 -0
  46. package/test/dname.js +53 -0
  47. package/test/dnskey.js +44 -0
  48. package/test/ds.js +44 -0
  49. package/test/fake.js +26 -0
  50. package/test/hinfo.js +75 -0
  51. package/test/ipseckey.js +115 -0
  52. package/test/key.js +37 -0
  53. package/test/loc.js +71 -0
  54. package/test/mx.js +75 -0
  55. package/test/naptr.js +40 -0
  56. package/test/ns.js +53 -0
  57. package/test/nsec.js +38 -0
  58. package/test/nsec3.js +26 -0
  59. package/test/nsec3param.js +26 -0
  60. package/test/openpgpkey.js +35 -0
  61. package/test/ptr.js +54 -0
  62. package/test/rr.js +196 -0
  63. package/test/smimea.js +45 -0
  64. package/test/soa.js +77 -0
  65. package/test/spf.js +48 -0
  66. package/test/srv.js +81 -0
  67. package/test/sshfp.js +62 -0
  68. package/test/tinydns.js +140 -0
  69. package/test/tlsa.js +54 -0
  70. package/test/txt.js +70 -0
  71. package/test/uri.js +61 -0
@@ -0,0 +1,84 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class NSEC3PARAM extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ if (opts === null) return
8
+ }
9
+
10
+ /****** Resource record specific setters *******/
11
+ setHashAlgoritm (val) {
12
+ // Hash Algorithm is a single octet.
13
+ // The Hash Algorithm field is represented as an unsigned decimal integer.
14
+ if (!val) throw new Error(`NSEC3PARAM: 'hash algorithm' is required, ${this.citeRFC()}`)
15
+
16
+ this.is8bitInt('NSEC3PARAM', 'hash algorithm', val)
17
+
18
+ this.set('hash algorithm', val)
19
+ }
20
+
21
+ setFlags (val) {
22
+ // The Flags field is represented as an unsigned decimal integer.
23
+ if (!val) throw new Error(`NSEC3PARAM: 'flags' is required, ${this.citeRFC()}`)
24
+
25
+ this.is8bitInt('NSEC3PARAM', 'flags', val)
26
+
27
+ this.set('flags', val)
28
+ }
29
+
30
+ setIterations (val) {
31
+ // The Iterations field is represented as an unsigned decimal integer. 0-65535
32
+ if (!val) throw new Error(`NSEC3PARAM: 'iterations' is required, ${this.citeRFC()}`)
33
+
34
+ this.is16bitInt('NSEC3PARAM', 'iterations', val)
35
+
36
+ this.set('iterations', val)
37
+ }
38
+
39
+ setSalt (val) {
40
+ // The Salt field is represented as a sequence of case-insensitive
41
+ // hexadecimal digits. Whitespace is not allowed within the
42
+ // sequence. The Salt field is represented as "-" (without the
43
+ // quotes) when the Salt Length field has a value of 0
44
+ this.set('salt', val)
45
+ }
46
+
47
+ getDescription () {
48
+ return 'Next Secure Parameters'
49
+ }
50
+
51
+ getRdataFields (arg) {
52
+ return [ 'hash algorithm', 'flags', 'iterations', 'salt' ]
53
+ }
54
+
55
+ getRFCs () {
56
+ return [ 5155 ]
57
+ }
58
+
59
+ getTypeId () {
60
+ return 51
61
+ }
62
+
63
+ /****** IMPORTERS *******/
64
+
65
+ fromBind (str) {
66
+ // test.example.com 3600 IN NSEC3PARAM
67
+ const [ owner, ttl, c, type ] = str.split(/\s+/)
68
+ return new NSEC3PARAM({
69
+ owner,
70
+ ttl : parseInt(ttl, 10),
71
+ class : c,
72
+ type : type,
73
+ 'hash algorithm' : '',
74
+ 'flags' : '',
75
+ 'iterations' : '',
76
+ 'salt' : '',
77
+ 'next hashed owner name': '',
78
+ 'type bit maps' : '',
79
+ })
80
+ }
81
+
82
+ /****** EXPORTERS *******/
83
+
84
+ }
@@ -0,0 +1,44 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class OPENPGPKEY extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setPublicKey (val) {
11
+ this.set('public key', val)
12
+ }
13
+
14
+ getDescription () {
15
+ return 'OpenPGP Public Key'
16
+ }
17
+
18
+ getRdataFields () {
19
+ return [ 'public key' ]
20
+ }
21
+
22
+ getRFCs () {
23
+ return [ 4880, 7929 ]
24
+ }
25
+
26
+ getTypeId () {
27
+ return 61
28
+ }
29
+
30
+ /****** IMPORTERS *******/
31
+ fromBind (str) {
32
+ // test.example.com 3600 IN OPENPGPKEY <base64 public key>
33
+ const [ owner, ttl, c, type, privatekey ] = str.split(/\s+/)
34
+ return new OPENPGPKEY({
35
+ owner,
36
+ ttl : parseInt(ttl, 10),
37
+ class : c,
38
+ type : type,
39
+ 'private key': privatekey,
40
+ })
41
+ }
42
+
43
+ /****** EXPORTERS *******/
44
+ }
package/rr/ptr.js ADDED
@@ -0,0 +1,65 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class PTR extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setDname (val) {
11
+ this.isFullyQualified('PTR', 'dname', val)
12
+ this.isValidHostname('PTR', 'dname', val)
13
+
14
+ // RFC 4034: letters in the DNS names are lower cased
15
+ this.set('dname', val.toLowerCase())
16
+ }
17
+
18
+ getDescription () {
19
+ return 'Pointer'
20
+ }
21
+
22
+ getRdataFields (arg) {
23
+ return [ 'dname' ]
24
+ }
25
+
26
+ getRFCs () {
27
+ return [ 1035 ]
28
+ }
29
+
30
+ getTypeId () {
31
+ return 12
32
+ }
33
+
34
+ /****** IMPORTERS *******/
35
+ fromTinydns (opts) {
36
+ // ^fqdn:p:ttl:timestamp:lo
37
+ const [ fqdn, p, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
38
+
39
+ return new PTR({
40
+ owner : this.fullyQualify(fqdn),
41
+ ttl : parseInt(ttl, 10),
42
+ type : 'PTR',
43
+ dname : this.fullyQualify(p),
44
+ timestamp: ts,
45
+ location : loc !== '' && loc !== '\n' ? loc : '',
46
+ })
47
+ }
48
+
49
+ fromBind (opts) {
50
+ // test.example.com 3600 IN PTR dname
51
+ const [ owner, ttl, c, type, dname ] = opts.bindline.split(/\s+/)
52
+ return new PTR({
53
+ owner,
54
+ ttl : parseInt(ttl, 10),
55
+ class: c,
56
+ type : type,
57
+ dname: dname,
58
+ })
59
+ }
60
+
61
+ /****** EXPORTERS *******/
62
+ toTinydns () {
63
+ return `^${this.getTinyFQDN('owner')}:${this.getTinyFQDN('dname')}:${this.getTinydnsPostamble()}\n`
64
+ }
65
+ }
package/rr/rrsig.js ADDED
@@ -0,0 +1,101 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class RRSIG extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setTypeCovered (val) {
11
+ // a 2 octet Type Covered field
12
+ if (!val) throw new Error(`RRSIG: 'type covered' is required`)
13
+ if (val.length > 2) throw new Error(`RRSIG: 'type covered' is too long, ${this.citeRFC()}`)
14
+
15
+ this.set('type covered', val)
16
+ }
17
+
18
+ setAlgorithm (val) {
19
+ // a 1 octet Algorithm field
20
+ // 1=RSA/MD5, 2=DH, 3=RRSIGA/SHA-1, 4=EC, 5=RSA/SHA-1
21
+ if (![ 1,2,3,4,5,253,254 ].includes(val))
22
+ throw new Error(`RRSIG: algorithm invalid, ${this.citeRFC()}`)
23
+
24
+ this.set('algorithm', val)
25
+ }
26
+
27
+ setLabels (val) {
28
+ // a 1 octet Labels field
29
+ this.is8bitInt('RRSIG', 'labels', val)
30
+
31
+ this.set('labels', val)
32
+ }
33
+
34
+ setOriginalTtl (val) {
35
+ // a 4 octet Original TTL field
36
+ this.is32bitInt('RRSIG', 'original ttl', val)
37
+
38
+ this.set('original ttl', val)
39
+ }
40
+
41
+ setSignatureExpiration (val) {
42
+ // a 4 octet Signature Expiration field
43
+ this.set('signature expiration', val)
44
+ }
45
+
46
+ setSignatureInception (val) {
47
+ // a 4 octet Signature Inception field
48
+ this.set('signature inception', val)
49
+ }
50
+
51
+ setKeyTag (val) {
52
+ // a 2 octet Key tag
53
+ this.set('key tag', val)
54
+ }
55
+
56
+ setSignersName (val) {
57
+ // the Signer's Name field
58
+ this.set('signers name', val)
59
+ }
60
+
61
+ setSignature (val) {
62
+ // the Signature field.
63
+
64
+ this.set('signature', val)
65
+ }
66
+
67
+ getDescription () {
68
+ return 'Resource Record Signature'
69
+ }
70
+
71
+ getRdataFields (arg) {
72
+ return [
73
+ 'type covered', 'algorithm', 'labels', 'original ttl', 'signature expiration',
74
+ 'signature inception', 'key tag', 'signers name', 'signature',
75
+ ]
76
+ }
77
+
78
+ getRFCs () {
79
+ return [ 4034 ]
80
+ }
81
+
82
+ getTypeId () {
83
+ return 46
84
+ }
85
+
86
+ /****** IMPORTERS *******/
87
+
88
+ // fromBind (str) {
89
+ // // test.example.com 3600 IN RRSIG ...
90
+ // const [ owner, ttl, c, type ] = str.split(/\s+/)
91
+ // return new RRSIG({
92
+ // owner,
93
+ // ttl : parseInt(ttl, 10),
94
+ // class : c,
95
+ // type : type,
96
+ // })
97
+ // }
98
+
99
+ /****** EXPORTERS *******/
100
+
101
+ }
package/rr/sig.js ADDED
@@ -0,0 +1,100 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class SIG extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setTypeCovered (val) {
11
+ // a 2 octet Type Covered field
12
+ if (!val) throw new Error(`SIG: 'type covered' is required`)
13
+
14
+ this.set('type covered', val)
15
+ }
16
+
17
+ setAlgorithm (val) {
18
+ // a 1 octet Algorithm field
19
+
20
+ this.is8bitInt('SIG', 'labels', val)
21
+
22
+ this.set('algorithm', val)
23
+ }
24
+
25
+ setLabels (val) {
26
+ // a 1 octet Labels field
27
+ this.is8bitInt('SIG', 'labels', val)
28
+
29
+ this.set('labels', val)
30
+ }
31
+
32
+ setOriginalTtl (val) {
33
+ // a 4 octet Original TTL field
34
+ this.is32bitInt('SIG', 'original ttl', val)
35
+
36
+ this.set('original ttl', val)
37
+ }
38
+
39
+ setSignatureExpiration (val) {
40
+ // a 4 octet Signature Expiration field
41
+ this.set('signature expiration', val)
42
+ }
43
+
44
+ setSignatureInception (val) {
45
+ // a 4 octet Signature Inception field
46
+ this.set('signature inception', val)
47
+ }
48
+
49
+ setKeyTag (val) {
50
+ // a 2 octet Key tag
51
+ this.set('key tag', val)
52
+ }
53
+
54
+ setSignersName (val) {
55
+ // the domain name of the signer generating the SIG RR
56
+
57
+ // RFC 4034: letters in the DNS names are lower cased
58
+ this.set('signers name', val.toLowerCase())
59
+ }
60
+
61
+ setSignature (val) {
62
+ // the Signature field.
63
+
64
+ this.set('signature', val)
65
+ }
66
+
67
+ getDescription () {
68
+ return 'Signature'
69
+ }
70
+
71
+ getRdataFields (arg) {
72
+ return [
73
+ 'type covered', 'algorithm', 'labels', 'original ttl', 'signature expiration',
74
+ 'signature inception', 'key tag', 'signers name', 'signature',
75
+ ]
76
+ }
77
+
78
+ getRFCs () {
79
+ return [ 2535 ]
80
+ }
81
+
82
+ getTypeId () {
83
+ return 24
84
+ }
85
+
86
+ /****** IMPORTERS *******/
87
+ // fromBind (str) {
88
+ // // test.example.com 3600 IN SIG ...
89
+ // const [ owner, ttl, c, type ] = str.split(/\s+/)
90
+ // return new SIG({
91
+ // owner,
92
+ // ttl : parseInt(ttl, 10),
93
+ // class : c,
94
+ // type : type,
95
+ // })
96
+ // }
97
+
98
+ /****** EXPORTERS *******/
99
+
100
+ }
package/rr/smimea.js ADDED
@@ -0,0 +1,73 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class SMIMEA extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setCertificateUsage (val) {
11
+ if (![ 0,1,2,3 ].includes(val))
12
+ throw new Error(`SMIMEA: certificate usage invalid, ${this.citeRFC()}`)
13
+
14
+ this.set('certificate usage', val)
15
+ }
16
+
17
+ setSelector (val) {
18
+ if (![ 0,1 ].includes(val))
19
+ throw new Error(`SMIMEA: selector invalid, ${this.citeRFC()}`)
20
+
21
+ this.set('selector', val)
22
+ }
23
+
24
+ setMatchingType (val) {
25
+ if (![ 0,1,2 ].includes(val))
26
+ throw new Error(`SMIMEA: matching type, ${this.citeRFC()}`)
27
+
28
+ this.set('matching type', val)
29
+ }
30
+
31
+ setCertificateAssociationData (val) {
32
+ this.set('certificate association data', val)
33
+ }
34
+
35
+
36
+ getDescription () {
37
+ return 'S/MIME cert association'
38
+ }
39
+
40
+ getRdataFields (arg) {
41
+ return [ 'certificate usage', 'selector', 'matching type', 'certificate association data' ]
42
+ }
43
+
44
+ getRFCs () {
45
+ return [ 8162 ]
46
+ }
47
+
48
+ getTypeId () {
49
+ return 53
50
+ }
51
+
52
+ getQuotedFields () {
53
+ return [ ]
54
+ }
55
+
56
+ /****** IMPORTERS *******/
57
+
58
+ fromBind (opts) {
59
+ // test.example.com 3600 IN SMIMEA, usage, selector, match, data
60
+ const [ owner, ttl, c, type, usage, selector, match ] = opts.bindline.split(/\s+/)
61
+ return new SMIMEA({
62
+ owner,
63
+ ttl : parseInt(ttl, 10),
64
+ class : c,
65
+ type : type,
66
+ 'certificate usage' : parseInt(usage, 10),
67
+ selector : parseInt(selector, 10),
68
+ 'matching type' : parseInt(match , 10),
69
+ 'certificate association data': opts.bindline.split(/\s+/).slice(7).join(' ').trim(),
70
+ })
71
+ }
72
+
73
+ }
package/rr/soa.js ADDED
@@ -0,0 +1,140 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class SOA extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ }
8
+
9
+ /****** Resource record specific setters *******/
10
+ setMinimum (val) {
11
+ // minimum (used for negative caching, since RFC 2308)
12
+ // RFC 1912 sugggests 1-5 days
13
+ // RIPE recommends 3600 (1 hour)
14
+ this.is32bitInt('SOA', 'minimum', val)
15
+
16
+ this.set('minimum', val)
17
+ }
18
+
19
+ setMname (val) {
20
+ // MNAME (primary NS)
21
+ this.isValidHostname('SOA', 'MNAME', val)
22
+ this.isFullyQualified('SOA', 'MNAME', val)
23
+
24
+ // RFC 4034: letters in the DNS names are lower cased
25
+ this.set('mname', val.toLowerCase())
26
+ }
27
+
28
+ setRname (val) {
29
+ // RNAME (email of admin) (escape . with \)
30
+ this.isValidHostname('SOA', 'RNAME', val)
31
+ this.isFullyQualified('SOA', 'RNAME', val)
32
+ if (/@/.test(val)) throw new Error(`SOA rname replaces @ with a . (dot), ${this.citeRFC()}`)
33
+
34
+ // RFC 4034: letters in the DNS names are lower cased
35
+ this.set('rname', val.toLowerCase())
36
+ }
37
+
38
+ setSerial (val) {
39
+ this.is32bitInt('SOA', 'serial', val)
40
+
41
+ this.set('serial', val)
42
+ }
43
+
44
+ setRefresh (val) {
45
+ // refresh (seconds after which to check with master for update)
46
+ // RFC 1912 suggests 20 min to 12 hours
47
+ // RIPE recommends 86400 (24 hours)
48
+ this.is32bitInt('SOA', 'refresh', val)
49
+
50
+ this.set('refresh', val)
51
+ }
52
+
53
+ setRetry (val) {
54
+ // seconds after which to retry serial # update
55
+ // RIPE recommends 7200 seconds (2 hours)
56
+
57
+ this.is32bitInt('SOA', 'retry', val)
58
+
59
+ this.set('retry', val)
60
+ }
61
+
62
+ setExpire (val) {
63
+ // seconds after which secondary should drop zone if no master response
64
+ // RFC 1912 suggests 2-4 weeks
65
+ // RIPE suggests 3600000 (1,000 hours, 6 weeks)
66
+ this.is32bitInt('SOA', 'expire', val)
67
+
68
+ this.set('expire', val)
69
+ }
70
+
71
+ getDescription () {
72
+ return 'Start Of Authority'
73
+ }
74
+
75
+ getRdataFields (arg) {
76
+ return [ 'mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum' ]
77
+ }
78
+
79
+ getRFCs () {
80
+ return [ 1035, 2308 ]
81
+ }
82
+
83
+ getTypeId () {
84
+ return 6
85
+ }
86
+
87
+ /****** IMPORTERS *******/
88
+ fromBind (opts) {
89
+ // example.com TTL IN SOA mname rname serial refresh retry expire minimum
90
+ const [ owner, ttl, c, type, mname, rname, serial, refresh, retry, expire, minimum ] = opts.bindline.split(/[\s+]/)
91
+
92
+ return new SOA({
93
+ owner,
94
+ ttl : parseInt(ttl) || parseInt(minimum),
95
+ class : c,
96
+ type,
97
+ mname,
98
+ rname,
99
+ serial : parseInt(serial , 10),
100
+ refresh: parseInt(refresh, 10),
101
+ retry : parseInt(retry , 10),
102
+ expire : parseInt(expire , 10),
103
+ minimum: parseInt(minimum, 10),
104
+ })
105
+ }
106
+
107
+ fromTinydns (opts) {
108
+ // Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:time:lo
109
+ const [ fqdn, mname, rname, ser, ref, ret, exp, min, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
110
+
111
+ return new SOA({
112
+ owner : this.fullyQualify(fqdn),
113
+ ttl : parseInt(ttl, 10),
114
+ type : 'SOA',
115
+ mname : this.fullyQualify(mname),
116
+ rname : this.fullyQualify(rname),
117
+ serial : parseInt(ser || opts.default?.serial, 10),
118
+ refresh : parseInt(ref, 10) || 16384,
119
+ retry : parseInt(ret, 10) || 2048,
120
+ expire : parseInt(exp, 10) || 1048576,
121
+ minimum : parseInt(min, 10) || 2560,
122
+ timestamp: parseInt(ts) || '',
123
+ location : loc !== '' && loc !== '\n' ? loc : '',
124
+ })
125
+ }
126
+
127
+ /****** EXPORTERS *******/
128
+ toBind (zone_opts) {
129
+ const numFields = [ 'serial', 'refresh', 'retry', 'expire', 'minimum' ]
130
+ return `${this.getFQDN('owner', zone_opts)}\t${this.get('ttl')}\t${this.get('class')}\tSOA\t${this.getFQDN('mname', zone_opts)}\t${this.getFQDN('rname', zone_opts)}${numFields.map(f => '\t' + this.get(f) ).join('')}\n`
131
+ }
132
+
133
+ toMaraDNS () {
134
+ return `${this.get('owner')}\t SOA\t${this.getRdataFields().map(f => this.getQuoted(f)).join('\t')} ~\n`
135
+ }
136
+
137
+ toTinydns () {
138
+ return `Z${this.getTinyFQDN('owner')}:${this.getTinyFQDN('mname')}:${this.getTinyFQDN('rname')}:${this.getEmpty('serial')}:${this.getEmpty('refresh')}:${this.getEmpty('retry')}:${this.getEmpty('expire')}:${this.getEmpty('minimum')}:${this.getTinydnsPostamble()}\n`
139
+ }
140
+ }
package/rr/spf.js ADDED
@@ -0,0 +1,54 @@
1
+ // obsoleted by RFC 7208
2
+
3
+ import TXT from './txt.js'
4
+
5
+ import * as TINYDNS from '../lib/tinydns.js'
6
+
7
+ export default class SPF extends TXT {
8
+ constructor (opts) {
9
+ super(opts)
10
+ }
11
+
12
+ /****** Resource record specific setters *******/
13
+ setData (val) {
14
+ this.set('data', val)
15
+ }
16
+
17
+ getDescription () {
18
+ return 'Sender Policy Framework'
19
+ }
20
+
21
+ getRdataFields (arg) {
22
+ return [ 'data' ]
23
+ }
24
+
25
+ getRFCs () {
26
+ return [ 4408, 7208 ]
27
+ }
28
+
29
+ getTypeId () {
30
+ return 99
31
+ }
32
+
33
+ /****** IMPORTERS *******/
34
+ fromTinydns (opts) {
35
+ // SPF via generic, :fqdn:n:rdata:ttl:timestamp:lo
36
+ const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
37
+ if (n != 99) throw new Error('SPF fromTinydns, invalid n')
38
+
39
+ return new SPF({
40
+ type : 'SPF',
41
+ owner : this.fullyQualify(fqdn),
42
+ data : TINYDNS.octalToChar(rdata),
43
+ ttl : parseInt(ttl, 10),
44
+ timestamp: ts,
45
+ location : loc !== '' && loc !== '\n' ? loc : '',
46
+ })
47
+ }
48
+
49
+ /****** EXPORTERS *******/
50
+ toTinydns () {
51
+ const rdata = TINYDNS.escapeOctal(new RegExp(/[\r\n\t:\\/]/, 'g'), this.get('data'))
52
+ return this.getTinydnsGeneric(rdata)
53
+ }
54
+ }