-
Notifications
You must be signed in to change notification settings - Fork 67
/
Copy pathconvert.js
190 lines (162 loc) · 4.58 KB
/
convert.js
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
'use strict'
const { Buffer } = require('buffer')
const ip = require('./ip')
const protocols = require('./protocols-table')
const CID = require('cids')
const multibase = require('multibase')
const varint = require('varint')
module.exports = Convert
// converts (serializes) addresses
function Convert (proto, a) {
if (a instanceof Buffer) {
return Convert.toString(proto, a)
} else {
return Convert.toBuffer(proto, a)
}
}
Convert.toString = function convertToString (proto, buf) {
proto = protocols(proto)
switch (proto.code) {
case 4: // ipv4
case 41: // ipv6
return buf2ip(buf)
case 6: // tcp
case 273: // udp
case 33: // dccp
case 132: // sctp
return buf2port(buf)
case 53: // dns
case 54: // dns4
case 55: // dns6
case 56: // dnsaddr
case 400: // unix
return buf2str(buf)
case 421: // ipfs
return buf2mh(buf)
case 444: // onion
return buf2onion(buf)
case 445: // onion3
return buf2onion(buf)
default:
return buf.toString('hex') // no clue. convert to hex
}
}
Convert.toBuffer = function convertToBuffer (proto, str) {
proto = protocols(proto)
switch (proto.code) {
case 4: // ipv4
return ip2buf(str)
case 41: // ipv6
return ip2buf(str)
case 6: // tcp
case 273: // udp
case 33: // dccp
case 132: // sctp
return port2buf(parseInt(str, 10))
case 53: // dns
case 54: // dns4
case 55: // dns6
case 56: // dnsaddr
case 400: // unix
return str2buf(str)
case 421: // ipfs
return mh2buf(str)
case 444: // onion
return onion2buf(str)
case 445: // onion3
return onion32buf(str)
default:
return Buffer.from(str, 'hex') // no clue. convert from hex
}
}
function ip2buf (ipString) {
if (!ip.isIP(ipString)) {
throw new Error('invalid ip address')
}
return ip.toBuffer(ipString)
}
function buf2ip (ipBuff) {
const ipString = ip.toString(ipBuff)
if (!ip.isIP(ipString)) {
throw new Error('invalid ip address')
}
return ipString
}
function port2buf (port) {
const buf = Buffer.alloc(2)
buf.writeUInt16BE(port, 0)
return buf
}
function buf2port (buf) {
return buf.readUInt16BE(0)
}
function str2buf (str) {
const buf = Buffer.from(str)
const size = Buffer.from(varint.encode(buf.length))
return Buffer.concat([size, buf])
}
function buf2str (buf) {
const size = varint.decode(buf)
buf = buf.slice(varint.decode.bytes)
if (buf.length !== size) {
throw new Error('inconsistent lengths')
}
return buf.toString()
}
function mh2buf (hash) {
// the address is a varint prefixed multihash string representation
const mh = new CID(hash).multihash
const size = Buffer.from(varint.encode(mh.length))
return Buffer.concat([size, mh])
}
function buf2mh (buf) {
const size = varint.decode(buf)
const address = buf.slice(varint.decode.bytes)
if (address.length !== size) {
throw new Error('inconsistent lengths')
}
return multibase.encode('base58btc', address).toString().slice(1)
}
function onion2buf (str) {
const addr = str.split(':')
if (addr.length !== 2) {
throw new Error('failed to parse onion addr: ' + addr + ' does not contain a port number')
}
if (addr[0].length !== 16) {
throw new Error('failed to parse onion addr: ' + addr[0] + ' not a Tor onion address.')
}
// onion addresses do not include the multibase prefix, add it before decoding
const buf = multibase.decode('b' + addr[0])
// onion port number
const port = parseInt(addr[1], 10)
if (port < 1 || port > 65536) {
throw new Error('Port number is not in range(1, 65536)')
}
const portBuf = port2buf(port)
return Buffer.concat([buf, portBuf])
}
function onion32buf (str) {
const addr = str.split(':')
if (addr.length !== 2) {
throw new Error('failed to parse onion addr: ' + addr + ' does not contain a port number')
}
if (addr[0].length !== 56) {
throw new Error('failed to parse onion addr: ' + addr[0] + ' not a Tor onion3 address.')
}
// onion addresses do not include the multibase prefix, add it before decoding
const buf = multibase.decode('b' + addr[0])
// onion port number
const port = parseInt(addr[1], 10)
if (port < 1 || port > 65536) {
throw new Error('Port number is not in range(1, 65536)')
}
const portBuf = port2buf(port)
return Buffer.concat([buf, portBuf])
}
function buf2onion (buf) {
const addrBytes = buf.slice(0, buf.length - 2)
const portBytes = buf.slice(buf.length - 2)
const addr = multibase.encode('base32', addrBytes).toString().slice(1)
const port = buf2port(portBytes)
return addr + ':' + port
}