@libp2p/interface-compliance-tests 3.0.5 → 3.0.7-05abd49f

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 (138) hide show
  1. package/README.md +14 -5
  2. package/dist/src/connection/index.d.ts +5 -0
  3. package/dist/src/connection/index.d.ts.map +1 -0
  4. package/dist/src/connection/index.js +151 -0
  5. package/dist/src/connection/index.js.map +1 -0
  6. package/dist/src/connection-encryption/index.d.ts +5 -0
  7. package/dist/src/connection-encryption/index.d.ts.map +1 -0
  8. package/dist/src/connection-encryption/index.js +71 -0
  9. package/dist/src/connection-encryption/index.js.map +1 -0
  10. package/dist/src/connection-encryption/utils/index.d.ts +3 -0
  11. package/dist/src/connection-encryption/utils/index.d.ts.map +1 -0
  12. package/dist/src/connection-encryption/utils/index.js +18 -0
  13. package/dist/src/connection-encryption/utils/index.js.map +1 -0
  14. package/dist/src/index.d.ts +1 -1
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/is-valid-tick.d.ts.map +1 -1
  17. package/dist/src/mocks/connection-encrypter.d.ts +3 -0
  18. package/dist/src/mocks/connection-encrypter.d.ts.map +1 -0
  19. package/dist/src/mocks/connection-encrypter.js +98 -0
  20. package/dist/src/mocks/connection-encrypter.js.map +1 -0
  21. package/dist/src/mocks/connection-gater.d.ts +3 -0
  22. package/dist/src/mocks/connection-gater.d.ts.map +1 -0
  23. package/dist/src/mocks/connection-gater.js +17 -0
  24. package/dist/src/mocks/connection-gater.js.map +1 -0
  25. package/dist/src/mocks/connection-manager.d.ts +27 -0
  26. package/dist/src/mocks/connection-manager.d.ts.map +1 -0
  27. package/dist/src/mocks/connection-manager.js +145 -0
  28. package/dist/src/mocks/connection-manager.js.map +1 -0
  29. package/dist/src/mocks/connection.d.ts +32 -0
  30. package/dist/src/mocks/connection.d.ts.map +1 -0
  31. package/dist/src/mocks/connection.js +162 -0
  32. package/dist/src/mocks/connection.js.map +1 -0
  33. package/dist/src/mocks/duplex.d.ts +3 -0
  34. package/dist/src/mocks/duplex.d.ts.map +1 -0
  35. package/dist/src/mocks/duplex.js +9 -0
  36. package/dist/src/mocks/duplex.js.map +1 -0
  37. package/dist/src/mocks/index.d.ts +13 -0
  38. package/dist/src/mocks/index.d.ts.map +1 -0
  39. package/dist/src/mocks/index.js +11 -0
  40. package/dist/src/mocks/index.js.map +1 -0
  41. package/dist/src/mocks/metrics.d.ts +3 -0
  42. package/dist/src/mocks/metrics.d.ts.map +1 -0
  43. package/dist/src/mocks/metrics.js +115 -0
  44. package/dist/src/mocks/metrics.js.map +1 -0
  45. package/dist/src/mocks/multiaddr-connection.d.ts +17 -0
  46. package/dist/src/mocks/multiaddr-connection.d.ts.map +1 -0
  47. package/dist/src/mocks/multiaddr-connection.js +51 -0
  48. package/dist/src/mocks/multiaddr-connection.js.map +1 -0
  49. package/dist/src/mocks/muxer.d.ts +8 -0
  50. package/dist/src/mocks/muxer.d.ts.map +1 -0
  51. package/dist/src/mocks/muxer.js +341 -0
  52. package/dist/src/mocks/muxer.js.map +1 -0
  53. package/dist/src/mocks/peer-discovery.d.ts +22 -0
  54. package/dist/src/mocks/peer-discovery.d.ts.map +1 -0
  55. package/dist/src/mocks/peer-discovery.js +47 -0
  56. package/dist/src/mocks/peer-discovery.js.map +1 -0
  57. package/dist/src/mocks/registrar.d.ts +18 -0
  58. package/dist/src/mocks/registrar.d.ts.map +1 -0
  59. package/dist/src/mocks/registrar.js +66 -0
  60. package/dist/src/mocks/registrar.js.map +1 -0
  61. package/dist/src/mocks/upgrader.d.ts +10 -0
  62. package/dist/src/mocks/upgrader.d.ts.map +1 -0
  63. package/dist/src/mocks/upgrader.js +31 -0
  64. package/dist/src/mocks/upgrader.js.map +1 -0
  65. package/dist/src/peer-discovery/index.d.ts +5 -0
  66. package/dist/src/peer-discovery/index.d.ts.map +1 -0
  67. package/dist/src/peer-discovery/index.js +66 -0
  68. package/dist/src/peer-discovery/index.js.map +1 -0
  69. package/dist/src/stream-muxer/base-test.d.ts +5 -0
  70. package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
  71. package/dist/src/stream-muxer/base-test.js +153 -0
  72. package/dist/src/stream-muxer/base-test.js.map +1 -0
  73. package/dist/src/stream-muxer/close-test.d.ts +5 -0
  74. package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
  75. package/dist/src/stream-muxer/close-test.js +269 -0
  76. package/dist/src/stream-muxer/close-test.js.map +1 -0
  77. package/dist/src/stream-muxer/index.d.ts +5 -0
  78. package/dist/src/stream-muxer/index.d.ts.map +1 -0
  79. package/dist/src/stream-muxer/index.js +13 -0
  80. package/dist/src/stream-muxer/index.js.map +1 -0
  81. package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
  82. package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
  83. package/dist/src/stream-muxer/mega-stress-test.js +11 -0
  84. package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
  85. package/dist/src/stream-muxer/spawner.d.ts +4 -0
  86. package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
  87. package/dist/src/stream-muxer/spawner.js +36 -0
  88. package/dist/src/stream-muxer/spawner.js.map +1 -0
  89. package/dist/src/stream-muxer/stress-test.d.ts +5 -0
  90. package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
  91. package/dist/src/stream-muxer/stress-test.js +23 -0
  92. package/dist/src/stream-muxer/stress-test.js.map +1 -0
  93. package/dist/src/transport/dial-test.d.ts +5 -0
  94. package/dist/src/transport/dial-test.d.ts.map +1 -0
  95. package/dist/src/transport/dial-test.js +98 -0
  96. package/dist/src/transport/dial-test.js.map +1 -0
  97. package/dist/src/transport/filter-test.d.ts +5 -0
  98. package/dist/src/transport/filter-test.d.ts.map +1 -0
  99. package/dist/src/transport/filter-test.js +18 -0
  100. package/dist/src/transport/filter-test.js.map +1 -0
  101. package/dist/src/transport/index.d.ts +15 -0
  102. package/dist/src/transport/index.d.ts.map +1 -0
  103. package/dist/src/transport/index.js +11 -0
  104. package/dist/src/transport/index.js.map +1 -0
  105. package/dist/src/transport/listen-test.d.ts +5 -0
  106. package/dist/src/transport/listen-test.d.ts.map +1 -0
  107. package/dist/src/transport/listen-test.js +152 -0
  108. package/dist/src/transport/listen-test.js.map +1 -0
  109. package/package.json +66 -95
  110. package/src/connection/index.ts +184 -0
  111. package/src/connection-encryption/index.ts +97 -0
  112. package/src/connection-encryption/utils/index.ts +23 -0
  113. package/src/index.ts +1 -1
  114. package/src/is-valid-tick.ts +1 -1
  115. package/src/mocks/connection-encrypter.ts +113 -0
  116. package/src/mocks/connection-gater.ts +18 -0
  117. package/src/mocks/connection-manager.ts +209 -0
  118. package/src/mocks/connection.ts +218 -0
  119. package/src/mocks/duplex.ts +10 -0
  120. package/src/mocks/index.ts +12 -0
  121. package/src/mocks/metrics.ts +162 -0
  122. package/src/mocks/multiaddr-connection.ts +67 -0
  123. package/src/mocks/muxer.ts +447 -0
  124. package/src/mocks/peer-discovery.ts +60 -0
  125. package/src/mocks/registrar.ts +88 -0
  126. package/src/mocks/upgrader.ts +49 -0
  127. package/src/peer-discovery/index.ts +90 -0
  128. package/src/stream-muxer/base-test.ts +196 -0
  129. package/src/stream-muxer/close-test.ts +346 -0
  130. package/src/stream-muxer/index.ts +15 -0
  131. package/src/stream-muxer/mega-stress-test.ts +14 -0
  132. package/src/stream-muxer/spawner.ts +54 -0
  133. package/src/stream-muxer/stress-test.ts +27 -0
  134. package/src/transport/dial-test.ts +124 -0
  135. package/src/transport/filter-test.ts +25 -0
  136. package/src/transport/index.ts +25 -0
  137. package/src/transport/listen-test.ts +191 -0
  138. package/dist/typedoc-urls.json +0 -3
package/package.json CHANGED
@@ -1,24 +1,20 @@
1
1
  {
2
2
  "name": "@libp2p/interface-compliance-tests",
3
- "version": "3.0.5",
3
+ "version": "3.0.7-05abd49f",
4
4
  "description": "Compliance tests for JS libp2p interfaces",
5
5
  "license": "Apache-2.0 OR MIT",
6
- "homepage": "https://github.com/libp2p/js-libp2p-interfaces/tree/master/packages/interface-compliance-tests#readme",
6
+ "homepage": "https://github.com/libp2p/js-libp2p/tree/master/packages/interface-compliance-tests#readme",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/libp2p/js-libp2p-interfaces.git"
9
+ "url": "git+https://github.com/libp2p/js-libp2p.git"
10
10
  },
11
11
  "bugs": {
12
- "url": "https://github.com/libp2p/js-libp2p-interfaces/issues"
12
+ "url": "https://github.com/libp2p/js-libp2p/issues"
13
13
  },
14
14
  "keywords": [
15
15
  "interface",
16
16
  "libp2p"
17
17
  ],
18
- "engines": {
19
- "node": ">=16.0.0",
20
- "npm": ">=7.0.0"
21
- },
22
18
  "type": "module",
23
19
  "types": "./dist/src/index.d.ts",
24
20
  "typesVersions": {
@@ -48,13 +44,37 @@
48
44
  "types": "./dist/src/index.d.ts",
49
45
  "import": "./dist/src/index.js"
50
46
  },
47
+ "./connection": {
48
+ "types": "./dist/src/connection/index.d.ts",
49
+ "import": "./dist/src/connection/index.js"
50
+ },
51
+ "./connection-encryption": {
52
+ "types": "./dist/src/connection-encryption/index.d.ts",
53
+ "import": "./dist/src/connection-encryption/index.js"
54
+ },
51
55
  "./is-valid-tick": {
52
56
  "types": "./dist/src/is-valid-tick.d.ts",
53
57
  "import": "./dist/src/is-valid-tick.js"
54
58
  },
59
+ "./mocks": {
60
+ "types": "./dist/src/mocks/index.d.ts",
61
+ "import": "./dist/src/mocks/index.js"
62
+ },
63
+ "./peer-discovery": {
64
+ "types": "./dist/src/peer-discovery/index.d.ts",
65
+ "import": "./dist/src/peer-discovery/index.js"
66
+ },
55
67
  "./peers": {
56
68
  "types": "./dist/src/peers.d.ts",
57
69
  "import": "./dist/src/peers.js"
70
+ },
71
+ "./stream-muxer": {
72
+ "types": "./dist/src/stream-muxer/index.d.ts",
73
+ "import": "./dist/src/stream-muxer/index.js"
74
+ },
75
+ "./transport": {
76
+ "types": "./dist/src/transport/index.d.ts",
77
+ "import": "./dist/src/transport/index.js"
58
78
  }
59
79
  },
60
80
  "eslintConfig": {
@@ -63,100 +83,51 @@
63
83
  "sourceType": "module"
64
84
  }
65
85
  },
66
- "release": {
67
- "branches": [
68
- "master"
69
- ],
70
- "plugins": [
71
- [
72
- "@semantic-release/commit-analyzer",
73
- {
74
- "preset": "conventionalcommits",
75
- "releaseRules": [
76
- {
77
- "breaking": true,
78
- "release": "major"
79
- },
80
- {
81
- "revert": true,
82
- "release": "patch"
83
- },
84
- {
85
- "type": "feat",
86
- "release": "minor"
87
- },
88
- {
89
- "type": "fix",
90
- "release": "patch"
91
- },
92
- {
93
- "type": "docs",
94
- "release": "patch"
95
- },
96
- {
97
- "type": "test",
98
- "release": "patch"
99
- },
100
- {
101
- "type": "deps",
102
- "release": "patch"
103
- },
104
- {
105
- "scope": "no-release",
106
- "release": false
107
- }
108
- ]
109
- }
110
- ],
111
- [
112
- "@semantic-release/release-notes-generator",
113
- {
114
- "preset": "conventionalcommits",
115
- "presetConfig": {
116
- "types": [
117
- {
118
- "type": "feat",
119
- "section": "Features"
120
- },
121
- {
122
- "type": "fix",
123
- "section": "Bug Fixes"
124
- },
125
- {
126
- "type": "chore",
127
- "section": "Trivial Changes"
128
- },
129
- {
130
- "type": "docs",
131
- "section": "Documentation"
132
- },
133
- {
134
- "type": "deps",
135
- "section": "Dependencies"
136
- },
137
- {
138
- "type": "test",
139
- "section": "Tests"
140
- }
141
- ]
142
- }
143
- }
144
- ],
145
- "@semantic-release/changelog",
146
- "@semantic-release/npm",
147
- "@semantic-release/github",
148
- "@semantic-release/git"
149
- ]
150
- },
151
86
  "scripts": {
152
87
  "clean": "aegir clean",
153
88
  "lint": "aegir lint",
154
89
  "dep-check": "aegir dep-check",
155
90
  "build": "aegir build",
156
- "release": "aegir release"
91
+ "test": "aegir test",
92
+ "test:chrome": "aegir test -t browser --cov",
93
+ "test:chrome-webworker": "aegir test -t webworker",
94
+ "test:firefox": "aegir test -t browser -- --browser firefox",
95
+ "test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
96
+ "test:node": "aegir test -t node --cov",
97
+ "test:electron-main": "aegir test -t electron-main"
157
98
  },
158
99
  "dependencies": {
159
- "aegir": "^37.7.3"
100
+ "@libp2p/interface": "0.0.1-05abd49f",
101
+ "@libp2p/interface-internal": "0.0.1-05abd49f",
102
+ "@libp2p/logger": "2.1.1-05abd49f",
103
+ "@libp2p/multistream-select": "3.1.9-05abd49f",
104
+ "@libp2p/peer-collections": "3.0.2-05abd49f",
105
+ "@libp2p/peer-id": "2.0.3-05abd49f",
106
+ "@libp2p/peer-id-factory": "2.0.3-05abd49f",
107
+ "@multiformats/multiaddr": "^12.1.3",
108
+ "abortable-iterator": "^5.0.1",
109
+ "any-signal": "^4.1.1",
110
+ "delay": "^6.0.0",
111
+ "it-all": "^3.0.2",
112
+ "it-drain": "^3.0.2",
113
+ "it-handshake": "^4.1.3",
114
+ "it-map": "^3.0.3",
115
+ "it-ndjson": "^1.0.3",
116
+ "it-pair": "^2.0.6",
117
+ "it-pipe": "^3.0.1",
118
+ "it-pushable": "^3.1.3",
119
+ "it-stream-types": "^2.0.1",
120
+ "merge-options": "^3.0.4",
121
+ "p-defer": "^4.0.0",
122
+ "p-limit": "^4.0.0",
123
+ "p-wait-for": "^5.0.2",
124
+ "sinon": "^15.1.2",
125
+ "ts-sinon": "^2.0.2",
126
+ "uint8arraylist": "^2.4.3",
127
+ "uint8arrays": "^4.0.4"
128
+ },
129
+ "devDependencies": {
130
+ "aegir": "^39.0.10"
160
131
  },
161
132
  "typedoc": {
162
133
  "entryPoint": "./src/index.ts"
@@ -0,0 +1,184 @@
1
+ import { expect } from 'aegir/chai'
2
+ import sinon from 'sinon'
3
+ import { stubInterface } from 'ts-sinon'
4
+ import type { TestSetup } from '../index.js'
5
+ import type { Connection, Stream } from '@libp2p/interface/connection'
6
+
7
+ export default (test: TestSetup<Connection>): void => {
8
+ describe('connection', () => {
9
+ describe('open connection', () => {
10
+ let connection: Connection
11
+
12
+ beforeEach(async () => {
13
+ connection = await test.setup()
14
+ })
15
+
16
+ afterEach(async () => {
17
+ await connection.close()
18
+ await test.teardown()
19
+ })
20
+
21
+ it('should have properties set', () => {
22
+ expect(connection.id).to.exist()
23
+ expect(connection.remotePeer).to.exist()
24
+ expect(connection.remoteAddr).to.exist()
25
+ expect(connection.stat.status).to.equal('OPEN')
26
+ expect(connection.stat.timeline.open).to.exist()
27
+ expect(connection.stat.timeline.close).to.not.exist()
28
+ expect(connection.stat.direction).to.exist()
29
+ expect(connection.streams).to.eql([])
30
+ expect(connection.tags).to.eql([])
31
+ })
32
+
33
+ it('should get the metadata of an open connection', () => {
34
+ const stat = connection.stat
35
+
36
+ expect(stat.status).to.equal('OPEN')
37
+ expect(stat.direction).to.exist()
38
+ expect(stat.timeline.open).to.exist()
39
+ expect(stat.timeline.close).to.not.exist()
40
+ })
41
+
42
+ it('should return an empty array of streams', () => {
43
+ const streams = connection.streams
44
+
45
+ expect(streams).to.eql([])
46
+ })
47
+
48
+ it('should be able to create a new stream', async () => {
49
+ expect(connection.streams).to.be.empty()
50
+
51
+ const protocolToUse = '/echo/0.0.1'
52
+ const stream = await connection.newStream([protocolToUse])
53
+
54
+ expect(stream).to.have.nested.property('stat.protocol', protocolToUse)
55
+
56
+ const connStreams = connection.streams
57
+
58
+ expect(stream).to.exist()
59
+ expect(connStreams).to.exist()
60
+ expect(connStreams).to.have.lengthOf(1)
61
+ expect(connStreams[0]).to.equal(stream)
62
+ })
63
+ })
64
+
65
+ describe('close connection', () => {
66
+ let connection: Connection
67
+ let timelineProxy
68
+ const proxyHandler = {
69
+ set () {
70
+ // @ts-expect-error - TS fails to infer here
71
+ return Reflect.set(...arguments)
72
+ }
73
+ }
74
+
75
+ beforeEach(async () => {
76
+ timelineProxy = new Proxy({
77
+ open: Date.now() - 10,
78
+ upgraded: Date.now()
79
+ }, proxyHandler)
80
+
81
+ connection = await test.setup()
82
+ connection.stat.timeline = timelineProxy
83
+ })
84
+
85
+ afterEach(async () => {
86
+ await test.teardown()
87
+ })
88
+
89
+ it('should be able to close the connection after being created', async () => {
90
+ expect(connection.stat.timeline.close).to.not.exist()
91
+ await connection.close()
92
+
93
+ expect(connection.stat.timeline.close).to.exist()
94
+ expect(connection.stat.status).to.equal('CLOSED')
95
+ })
96
+
97
+ it('should be able to close the connection after opening a stream', async () => {
98
+ // Open stream
99
+ const protocol = '/echo/0.0.1'
100
+ await connection.newStream([protocol])
101
+
102
+ // Close connection
103
+ expect(connection.stat.timeline.close).to.not.exist()
104
+ await connection.close()
105
+
106
+ expect(connection.stat.timeline.close).to.exist()
107
+ expect(connection.stat.status).to.equal('CLOSED')
108
+ })
109
+
110
+ it('should properly track streams', async () => {
111
+ // Open stream
112
+ const protocol = '/echo/0.0.1'
113
+ const stream = await connection.newStream([protocol])
114
+ expect(stream).to.have.nested.property('stat.protocol', protocol)
115
+
116
+ // Close stream
117
+ stream.close()
118
+
119
+ expect(connection.streams.filter(s => s.id === stream.id)).to.be.empty()
120
+ })
121
+
122
+ it('should track outbound streams', async () => {
123
+ // Open stream
124
+ const protocol = '/echo/0.0.1'
125
+ const stream = await connection.newStream(protocol)
126
+ expect(stream).to.have.nested.property('stat.direction', 'outbound')
127
+ })
128
+
129
+ it.skip('should track inbound streams', async () => {
130
+ // Add an remotely opened stream
131
+ const stream = stubInterface<Stream>()
132
+ connection.addStream(stream)
133
+ expect(stream).to.have.property('direction', 'inbound')
134
+ })
135
+
136
+ it('should support a proxy on the timeline', async () => {
137
+ sinon.spy(proxyHandler, 'set')
138
+ expect(connection.stat.timeline.close).to.not.exist()
139
+
140
+ await connection.close()
141
+ // @ts-expect-error - fails to infer callCount
142
+ expect(proxyHandler.set.callCount).to.equal(1)
143
+ // @ts-expect-error - fails to infer getCall
144
+ const [obj, key, value] = proxyHandler.set.getCall(0).args
145
+ expect(obj).to.eql(connection.stat.timeline)
146
+ expect(key).to.equal('close')
147
+ expect(value).to.be.a('number').that.equals(connection.stat.timeline.close)
148
+ })
149
+
150
+ it('should fail to create a new stream if the connection is closing', async () => {
151
+ expect(connection.stat.timeline.close).to.not.exist()
152
+ const p = connection.close()
153
+
154
+ try {
155
+ const protocol = '/echo/0.0.1'
156
+ await connection.newStream([protocol])
157
+ } catch (err: any) {
158
+ expect(err).to.exist()
159
+ return
160
+ } finally {
161
+ await p
162
+ }
163
+
164
+ throw new Error('should fail to create a new stream if the connection is closing')
165
+ })
166
+
167
+ it('should fail to create a new stream if the connection is closed', async () => {
168
+ expect(connection.stat.timeline.close).to.not.exist()
169
+ await connection.close()
170
+
171
+ try {
172
+ const protocol = '/echo/0.0.1'
173
+ await connection.newStream([protocol])
174
+ } catch (err: any) {
175
+ expect(err).to.exist()
176
+ expect(err.code).to.equal('ERR_CONNECTION_CLOSED')
177
+ return
178
+ }
179
+
180
+ throw new Error('should fail to create a new stream if the connection is closing')
181
+ })
182
+ })
183
+ })
184
+ }
@@ -0,0 +1,97 @@
1
+ import { UnexpectedPeerError } from '@libp2p/interface/errors'
2
+ import * as PeerIdFactory from '@libp2p/peer-id-factory'
3
+ import { expect } from 'aegir/chai'
4
+ import all from 'it-all'
5
+ import { pipe } from 'it-pipe'
6
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
7
+ import peers from '../peers.js'
8
+ import { createMaConnPair } from './utils/index.js'
9
+ import type { TestSetup } from '../index.js'
10
+ import type { ConnectionEncrypter } from '@libp2p/interface/connection-encrypter'
11
+ import type { PeerId } from '@libp2p/interface/peer-id'
12
+
13
+ export default (common: TestSetup<ConnectionEncrypter>): void => {
14
+ describe('interface-connection-encrypter compliance tests', () => {
15
+ let crypto: ConnectionEncrypter
16
+ let localPeer: PeerId
17
+ let remotePeer: PeerId
18
+ let mitmPeer: PeerId
19
+
20
+ before(async () => {
21
+ [
22
+ crypto,
23
+ localPeer,
24
+ remotePeer,
25
+ mitmPeer
26
+ ] = await Promise.all([
27
+ common.setup(),
28
+ PeerIdFactory.createFromJSON(peers[0]),
29
+ PeerIdFactory.createFromJSON(peers[1]),
30
+ PeerIdFactory.createFromJSON(peers[2])
31
+ ])
32
+ })
33
+
34
+ after(async () => {
35
+ await common.teardown()
36
+ })
37
+
38
+ it('has a protocol string', () => {
39
+ expect(crypto.protocol).to.exist()
40
+ expect(crypto.protocol).to.be.a('string')
41
+ })
42
+
43
+ it('it wraps the provided duplex connection', async () => {
44
+ const [localConn, remoteConn] = createMaConnPair()
45
+
46
+ const [
47
+ inboundResult,
48
+ outboundResult
49
+ ] = await Promise.all([
50
+ crypto.secureInbound(remotePeer, localConn),
51
+ crypto.secureOutbound(localPeer, remoteConn, remotePeer)
52
+ ])
53
+
54
+ // Echo server
55
+ void pipe(inboundResult.conn, inboundResult.conn)
56
+
57
+ // Send some data and collect the result
58
+ const input = uint8ArrayFromString('data to encrypt')
59
+ const result = await pipe(
60
+ [input],
61
+ outboundResult.conn,
62
+ async (source) => all(source)
63
+ )
64
+
65
+ expect(result).to.eql([input])
66
+ })
67
+
68
+ it('should return the remote peer id', async () => {
69
+ const [localConn, remoteConn] = createMaConnPair()
70
+
71
+ const [
72
+ inboundResult,
73
+ outboundResult
74
+ ] = await Promise.all([
75
+ crypto.secureInbound(remotePeer, localConn),
76
+ crypto.secureOutbound(localPeer, remoteConn, remotePeer)
77
+ ])
78
+
79
+ // Inbound should return the initiator (local) peer
80
+ expect(inboundResult.remotePeer.toBytes()).to.equalBytes(localPeer.toBytes())
81
+ // Outbound should return the receiver (remote) peer
82
+ expect(outboundResult.remotePeer.toBytes()).to.equalBytes(remotePeer.toBytes())
83
+ })
84
+
85
+ it('inbound connections should verify peer integrity if known', async () => {
86
+ const [localConn, remoteConn] = createMaConnPair()
87
+
88
+ await Promise.all([
89
+ crypto.secureInbound(remotePeer, localConn, mitmPeer),
90
+ crypto.secureOutbound(localPeer, remoteConn, remotePeer)
91
+ ]).then(() => expect.fail(), (err) => {
92
+ expect(err).to.exist()
93
+ expect(err).to.have.property('code', UnexpectedPeerError.code)
94
+ })
95
+ })
96
+ })
97
+ }
@@ -0,0 +1,23 @@
1
+ import { multiaddr } from '@multiformats/multiaddr'
2
+ import { duplexPair } from 'it-pair/duplex'
3
+ import type { MultiaddrConnection } from '@libp2p/interface/connection'
4
+ import type { Duplex, Source } from 'it-stream-types'
5
+
6
+ export function createMaConnPair (): [MultiaddrConnection, MultiaddrConnection] {
7
+ const [local, remote] = duplexPair<Uint8Array>()
8
+
9
+ function duplexToMaConn (duplex: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>): MultiaddrConnection {
10
+ const output: MultiaddrConnection = {
11
+ ...duplex,
12
+ close: async () => {},
13
+ remoteAddr: multiaddr('/ip4/127.0.0.1/tcp/4001'),
14
+ timeline: {
15
+ open: Date.now()
16
+ }
17
+ }
18
+
19
+ return output
20
+ }
21
+
22
+ return [duplexToMaConn(local), duplexToMaConn(remote)]
23
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- export interface TestSetup<T, SetupArgs = {}> {
2
+ export interface TestSetup<T, SetupArgs = Record<string, unknown>> {
3
3
  setup: (args?: SetupArgs) => Promise<T>
4
4
  teardown: () => Promise<void>
5
5
  }
@@ -3,7 +3,7 @@
3
3
  * A tick is considered valid if it happened between now
4
4
  * and `ms` milliseconds ago
5
5
  */
6
- export function isValidTick (date?: number, ms: number = 5000) {
6
+ export function isValidTick (date?: number, ms: number = 5000): boolean {
7
7
  if (date == null) {
8
8
  throw new Error('date must be a number')
9
9
  }
@@ -0,0 +1,113 @@
1
+ import { UnexpectedPeerError } from '@libp2p/interface/errors'
2
+ import { peerIdFromBytes } from '@libp2p/peer-id'
3
+ import { multiaddr } from '@multiformats/multiaddr'
4
+ import { handshake } from 'it-handshake'
5
+ import map from 'it-map'
6
+ import { duplexPair } from 'it-pair/duplex'
7
+ import { pipe } from 'it-pipe'
8
+ import type { ConnectionEncrypter } from '@libp2p/interface/connection-encrypter'
9
+ import type { Transform, Source } from 'it-stream-types'
10
+
11
+ // A basic transform that does nothing to the data
12
+ const transform = <T>(): Transform<Source<T>, AsyncGenerator<T>> => {
13
+ return (source: Source<T>) => (async function * () {
14
+ for await (const chunk of source) {
15
+ yield chunk
16
+ }
17
+ })()
18
+ }
19
+
20
+ export function mockConnectionEncrypter (): ConnectionEncrypter {
21
+ const encrypter: ConnectionEncrypter = {
22
+ protocol: 'insecure',
23
+ secureInbound: async (localPeer, duplex, expectedPeer) => {
24
+ // 1. Perform a basic handshake.
25
+ const shake = handshake<Uint8Array>(duplex)
26
+ shake.write(localPeer.toBytes())
27
+ const remoteId = await shake.read()
28
+
29
+ if (remoteId == null) {
30
+ throw new Error('Could not read remote ID')
31
+ }
32
+
33
+ const remotePeer = peerIdFromBytes(remoteId.slice())
34
+ shake.rest()
35
+
36
+ if (expectedPeer?.equals(remotePeer) === false) {
37
+ throw new UnexpectedPeerError()
38
+ }
39
+
40
+ // 2. Create your encryption box/unbox wrapper
41
+ const wrapper = duplexPair<Uint8Array>()
42
+ const encrypt = transform<Uint8Array>() // Use transform iterables to modify data
43
+ const decrypt = transform<Uint8Array>()
44
+
45
+ void pipe(
46
+ wrapper[0], // We write to wrapper
47
+ encrypt, // The data is encrypted
48
+ shake.stream, // It goes to the remote peer
49
+ source => map(source, (list) => list.subarray()), // turn lists into arrays
50
+ decrypt, // Decrypt the incoming data
51
+ wrapper[0] // Pipe to the wrapper
52
+ )
53
+
54
+ return {
55
+ conn: {
56
+ ...wrapper[1],
57
+ close: async () => { },
58
+ localAddr: multiaddr('/ip4/127.0.0.1/tcp/4001'),
59
+ remoteAddr: multiaddr('/ip4/127.0.0.1/tcp/4002'),
60
+ timeline: {
61
+ open: Date.now()
62
+ },
63
+ conn: true
64
+ },
65
+ remotePeer,
66
+ remoteExtensions: {}
67
+ }
68
+ },
69
+ secureOutbound: async (localPeer, duplex, remotePeer) => {
70
+ // 1. Perform a basic handshake.
71
+ const shake = handshake<Uint8Array>(duplex)
72
+ shake.write(localPeer.toBytes())
73
+ const remoteId = await shake.read()
74
+
75
+ if (remoteId == null) {
76
+ throw new Error('Could not read remote ID')
77
+ }
78
+
79
+ shake.rest()
80
+
81
+ // 2. Create your encryption box/unbox wrapper
82
+ const wrapper = duplexPair<Uint8Array>()
83
+ const encrypt = transform<Uint8Array>()
84
+ const decrypt = transform<Uint8Array>()
85
+
86
+ void pipe(
87
+ wrapper[0], // We write to wrapper
88
+ encrypt, // The data is encrypted
89
+ shake.stream, // It goes to the remote peer
90
+ source => map(source, (list) => list.subarray()), // turn lists into arrays
91
+ decrypt, // Decrypt the incoming data
92
+ wrapper[0] // Pipe to the wrapper
93
+ )
94
+
95
+ return {
96
+ conn: {
97
+ ...wrapper[1],
98
+ close: async () => { },
99
+ localAddr: multiaddr('/ip4/127.0.0.1/tcp/4001'),
100
+ remoteAddr: multiaddr('/ip4/127.0.0.1/tcp/4002'),
101
+ timeline: {
102
+ open: Date.now()
103
+ },
104
+ conn: true
105
+ },
106
+ remotePeer: peerIdFromBytes(remoteId.slice()),
107
+ remoteExtensions: {}
108
+ }
109
+ }
110
+ }
111
+
112
+ return encrypter
113
+ }
@@ -0,0 +1,18 @@
1
+ import type { ConnectionGater } from '@libp2p/interface/connection-gater'
2
+
3
+ export function mockConnectionGater (): ConnectionGater {
4
+ return {
5
+ denyDialPeer: async () => Promise.resolve(false),
6
+ denyDialMultiaddr: async () => Promise.resolve(false),
7
+ denyInboundConnection: async () => Promise.resolve(false),
8
+ denyOutboundConnection: async () => Promise.resolve(false),
9
+ denyInboundEncryptedConnection: async () => Promise.resolve(false),
10
+ denyOutboundEncryptedConnection: async () => Promise.resolve(false),
11
+ denyInboundUpgradedConnection: async () => Promise.resolve(false),
12
+ denyOutboundUpgradedConnection: async () => Promise.resolve(false),
13
+ denyInboundRelayReservation: async () => Promise.resolve(false),
14
+ denyOutboundRelayedConnection: async () => Promise.resolve(false),
15
+ denyInboundRelayedConnection: async () => Promise.resolve(false),
16
+ filterMultiaddrForPeer: async () => Promise.resolve(true)
17
+ }
18
+ }