Skip to content

Commit d4d3d9b

Browse files
authored
feat: add unix protocol support and update protocol table (#84)
* feat: update protocol table to match latest * feat: add unix protocol and path support * chore: fix lint
1 parent ebd35c3 commit d4d3d9b

File tree

5 files changed

+141
-12
lines changed

5 files changed

+141
-12
lines changed

src/codec.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ function stringToStringTuples (str) {
5252
throw ParseError('invalid address: ' + str)
5353
}
5454

55+
// if it's a path proto, take the rest
56+
if (proto.path) {
57+
tuples.push([
58+
part,
59+
// TODO: should we need to check each path part to see if it's a proto?
60+
// This would allow for other protocols to be added after a unix path,
61+
// however it would have issues if the path had a protocol name in the path
62+
cleanPath(parts.slice(p).join('/'))
63+
])
64+
break
65+
}
66+
5567
tuples.push([part, parts[p]])
5668
}
5769

@@ -69,7 +81,7 @@ function stringTuplesToString (tuples) {
6981
}
7082
})
7183

72-
return '/' + parts.join('/')
84+
return cleanPath(parts.join('/'))
7385
}
7486

7587
// [[str name, str addr]... ] -> [[int code, Buffer]... ]

src/convert.js

+4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ Convert.toString = function convertToString (proto, buf) {
3030
case 132: // sctp
3131
return buf2port(buf)
3232

33+
case 53: // dns
3334
case 54: // dns4
3435
case 55: // dns6
3536
case 56: // dnsaddr
37+
case 400: // unix
3638
return buf2str(buf)
3739

3840
case 421: // ipfs
@@ -56,9 +58,11 @@ Convert.toBuffer = function convertToBuffer (proto, str) {
5658
case 132: // sctp
5759
return port2buf(parseInt(str, 10))
5860

61+
case 53: // dns
5962
case 54: // dns4
6063
case 55: // dns6
6164
case 56: // dnsaddr
65+
case 400: // unix
6266
return str2buf(str)
6367

6468
case 421: // ipfs

src/index.js

+27
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,33 @@ Multiaddr.prototype.getPeerId = function getPeerId () {
255255
return b58str
256256
}
257257

258+
/**
259+
* Extract the path if the multiaddr contains one
260+
*
261+
* @return {String|null} path - The path of the multiaddr, or null if no path protocol is present
262+
* @example
263+
* const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock')
264+
* // <Multiaddr 0408080808060438 - /ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock>
265+
*
266+
* // should return utf8 string or null if the id is missing or invalid
267+
* const path = mh1.getPath()
268+
*/
269+
Multiaddr.prototype.getPath = function getPath () {
270+
let path = null
271+
try {
272+
path = this.stringTuples().filter((tuple) => {
273+
const proto = protocols(tuple[0])
274+
if (proto.path) {
275+
return true
276+
}
277+
})[0][1]
278+
} catch (e) {
279+
path = null
280+
}
281+
282+
return path
283+
}
284+
258285
/**
259286
* Checks if two Multiaddrs are the same
260287
*

src/protocols-table.js

+18-11
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,38 @@ Protocols.V = V
2525
Protocols.table = [
2626
[4, 32, 'ip4'],
2727
[6, 16, 'tcp'],
28-
[273, 16, 'udp'],
2928
[33, 16, 'dccp'],
3029
[41, 128, 'ip6'],
30+
[42, V, 'ip6zone'],
31+
[53, V, 'dns', 'resolvable'],
3132
[54, V, 'dns4', 'resolvable'],
3233
[55, V, 'dns6', 'resolvable'],
3334
[56, V, 'dnsaddr', 'resolvable'],
3435
[132, 16, 'sctp'],
35-
// all of the below use varint for size
36+
[273, 16, 'udp'],
37+
[275, 0, 'p2p-webrtc-star'],
38+
[276, 0, 'p2p-webrtc-direct'],
39+
[277, 0, 'p2p-stardust'],
40+
[290, 0, 'p2p-circuit'],
41+
[301, 0, 'udt'],
3642
[302, 0, 'utp'],
43+
[400, V, 'unix', false, 'path'],
3744
// `p2p` is the preferred name for 421
38-
[421, Protocols.lengthPrefixedVarSize, 'p2p'],
45+
[421, V, 'p2p'],
3946
// `ipfs` has been added after `p2p` so that it is used by default.
4047
// The reason for this is to provide better backwards support for
4148
// code bases that do not yet support the `p2p` proto name. Eventually
4249
// `p2p` should become the default.
43-
[421, Protocols.lengthPrefixedVarSize, 'ipfs'],
44-
[480, 0, 'http'],
50+
[421, V, 'ipfs'],
4551
[443, 0, 'https'],
52+
[444, 96, 'onion'],
53+
[445, 296, 'onion3'],
54+
[446, V, 'garlic64'],
4655
[460, 0, 'quic'],
4756
[477, 0, 'ws'],
4857
[478, 0, 'wss'],
4958
[479, 0, 'p2p-websocket-star'],
50-
[277, 0, 'p2p-stardust'],
51-
[275, 0, 'p2p-webrtc-star'],
52-
[276, 0, 'p2p-webrtc-direct'],
53-
[290, 0, 'p2p-circuit']
59+
[480, 0, 'http']
5460
]
5561

5662
Protocols.names = {}
@@ -65,12 +71,13 @@ Protocols.table.map(row => {
6571

6672
Protocols.object = p
6773

68-
function p (code, size, name, resolvable) {
74+
function p (code, size, name, resolvable, path) {
6975
return {
7076
code: code,
7177
size: size,
7278
name: name,
73-
resolvable: Boolean(resolvable)
79+
resolvable: Boolean(resolvable),
80+
path: Boolean(path)
7481
}
7582
}
7683

test/index.spec.js

+79
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,27 @@ describe('variants', () => {
260260
expect(addr.toString()).to.equal(str)
261261
})
262262

263+
it('ip4 + tcp + unix', () => {
264+
const str = '/ip4/127.0.0.1/tcp/80/unix/a/b/c/d/e/f'
265+
const addr = multiaddr(str)
266+
expect(addr).to.have.property('buffer')
267+
expect(addr.toString()).to.equal(str)
268+
})
269+
263270
it('ip6 + tcp + http', () => {
264271
const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/http'
265272
const addr = multiaddr(str)
266273
expect(addr).to.have.property('buffer')
267274
expect(addr.toString()).to.equal(str)
268275
})
269276

277+
it('ip6 + tcp + unix', () => {
278+
const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/unix/a/b/c/d/e/f'
279+
const addr = multiaddr(str)
280+
expect(addr).to.have.property('buffer')
281+
expect(addr.toString()).to.equal(str)
282+
})
283+
270284
it('ip4 + tcp + https', () => {
271285
const str = '/ip4/127.0.0.1/tcp/8000/https'
272286
const addr = multiaddr(str)
@@ -323,6 +337,13 @@ describe('variants', () => {
323337
expect(addr.toString()).to.equal(str.replace('/p2p/', '/ipfs/'))
324338
})
325339

340+
it('unix', () => {
341+
const str = '/unix/a/b/c/d/e'
342+
const addr = multiaddr(str)
343+
expect(addr).to.have.property('buffer')
344+
expect(addr.toString()).to.equal(str)
345+
})
346+
326347
it('p2p', () => {
327348
const str = '/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC'
328349
const addr = multiaddr(str)
@@ -413,11 +434,13 @@ describe('helpers', () => {
413434
.to.eql([{
414435
code: 4,
415436
name: 'ip4',
437+
path: false,
416438
size: 32,
417439
resolvable: false
418440
}, {
419441
code: 302,
420442
name: 'utp',
443+
path: false,
421444
size: 0,
422445
resolvable: false
423446
}])
@@ -429,16 +452,19 @@ describe('helpers', () => {
429452
).to.be.eql([{
430453
code: 4,
431454
name: 'ip4',
455+
path: false,
432456
size: 32,
433457
resolvable: false
434458
}, {
435459
code: 302,
436460
name: 'utp',
461+
path: false,
437462
size: 0,
438463
resolvable: false
439464
}, {
440465
code: 421,
441466
name: 'ipfs',
467+
path: false,
442468
size: -1,
443469
resolvable: false
444470
}])
@@ -450,16 +476,43 @@ describe('helpers', () => {
450476
).to.be.eql([{
451477
code: 4,
452478
name: 'ip4',
479+
path: false,
453480
size: 32,
454481
resolvable: false
455482
}, {
456483
code: 302,
457484
name: 'utp',
485+
path: false,
458486
size: 0,
459487
resolvable: false
460488
}, {
461489
code: 421,
462490
name: 'ipfs',
491+
path: false,
492+
size: -1,
493+
resolvable: false
494+
}])
495+
})
496+
497+
it('works with unix', () => {
498+
expect(
499+
multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos()
500+
).to.be.eql([{
501+
code: 4,
502+
name: 'ip4',
503+
path: false,
504+
size: 32,
505+
resolvable: false
506+
}, {
507+
code: 6,
508+
name: 'tcp',
509+
path: false,
510+
size: 16,
511+
resolvable: false
512+
}, {
513+
code: 400,
514+
name: 'unix',
515+
path: true,
463516
size: -1,
464517
resolvable: false
465518
}])
@@ -663,6 +716,26 @@ describe('helpers', () => {
663716
})
664717
})
665718

719+
describe('.getPath', () => {
720+
it('should return a path for unix', () => {
721+
expect(
722+
multiaddr('/unix/tmp/p2p.sock').getPath()
723+
).to.eql('/tmp/p2p.sock')
724+
})
725+
726+
it('should return a path for unix when other protos exist', () => {
727+
expect(
728+
multiaddr('/ip4/0.0.0.0/tcp/1234/unix/tmp/p2p.sock').getPath()
729+
).to.eql('/tmp/p2p.sock')
730+
})
731+
732+
it('should not return a path when no path proto exists', () => {
733+
expect(
734+
multiaddr('/ip4/0.0.0.0/tcp/1234/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPath()
735+
).to.eql(null)
736+
})
737+
})
738+
666739
describe('multiaddr.isMultiaddr', () => {
667740
it('handles different inputs', () => {
668741
expect(multiaddr.isMultiaddr(multiaddr('/'))).to.be.eql(true)
@@ -676,6 +749,12 @@ describe('helpers', () => {
676749
describe('resolvable multiaddrs', () => {
677750
describe('.isName', () => {
678751
it('valid name dns', () => {
752+
const str = '/dns/ipfs.io'
753+
const addr = multiaddr(str)
754+
expect(multiaddr.isName(addr)).to.equal(true)
755+
})
756+
757+
it('valid name dnsaddr', () => {
679758
const str = '/dnsaddr/ipfs.io'
680759
const addr = multiaddr(str)
681760
expect(multiaddr.isName(addr)).to.equal(true)

0 commit comments

Comments
 (0)