helia-coord 1.1.0
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/.on-save.json +8 -0
- package/PEDIGREE.md +3 -0
- package/README.md +3 -0
- package/config/bootstrap-circuit-relays.js +48 -0
- package/examples/start-external.js +56 -0
- package/index.js +129 -0
- package/lib/adapters/bch-adapter.js +94 -0
- package/lib/adapters/encryption-adapter.js +123 -0
- package/lib/adapters/gist.js +42 -0
- package/lib/adapters/index.js +66 -0
- package/lib/adapters/ipfs-adapter.js +263 -0
- package/lib/adapters/logs-adapter.js +44 -0
- package/lib/adapters/pubsub-adapter/README.md +86 -0
- package/lib/adapters/pubsub-adapter/about-adapter.js +117 -0
- package/lib/adapters/pubsub-adapter/index.js +275 -0
- package/lib/adapters/pubsub-adapter/messaging.js +389 -0
- package/lib/adapters/pubsub-adapter/msg-router.js +58 -0
- package/lib/adapters/pubsub-adapter/resend-msg.js +58 -0
- package/lib/controllers/index.js +24 -0
- package/lib/controllers/timer-controller.js +417 -0
- package/lib/entities/this-node-entity.js +102 -0
- package/lib/use-cases/index.js +36 -0
- package/lib/use-cases/peer-use-cases.js +146 -0
- package/lib/use-cases/pubsub-use-cases.js +56 -0
- package/lib/use-cases/relay-use-cases.js +479 -0
- package/lib/use-cases/schema.js +158 -0
- package/lib/use-cases/this-node-use-cases.js +443 -0
- package/lib/util/utils.js +12 -0
- package/package.json +52 -0
- package/test/mocks/adapter-mock.js +119 -0
- package/test/mocks/circuit-relay-mocks.js +67 -0
- package/test/mocks/ipfs-mock.js +46 -0
- package/test/mocks/peers-mock.js +75 -0
- package/test/mocks/pubsub-mocks.js +37 -0
- package/test/mocks/thisnode-mocks.js +82 -0
- package/test/mocks/use-case-mocks.js +24 -0
- package/test/unit/adapters/bch-adapter-unit.js +96 -0
- package/test/unit/adapters/encryption-adapter-unit.js +129 -0
- package/test/unit/adapters/gist.unit.adapters.js +58 -0
- package/test/unit/adapters/index-adapters-unit.js +79 -0
- package/test/unit/adapters/ipfs-adapter-unit.js +215 -0
- package/test/unit/adapters/logs-adapter-unit.js +55 -0
- package/test/unit/adapters/pubsub/about-adapter-unit.js +129 -0
- package/test/unit/adapters/pubsub/messaging-adapter-unit.js +576 -0
- package/test/unit/adapters/pubsub/pubsub-adapter-unit.js +367 -0
- package/test/unit/adapters/pubsub/resend-msg-adapter-unit.js +58 -0
- package/test/unit/controllers/controllers-index-unit.js +30 -0
- package/test/unit/controllers/timer-controller-unit.js +261 -0
- package/test/unit/entities/this-node.unit.entity.js +157 -0
- package/test/unit/index-unit.js +160 -0
- package/test/unit/use-cases/peer.unit.use-cases.js +186 -0
- package/test/unit/use-cases/pubsub.unit.use-cases.js +114 -0
- package/test/unit/use-cases/relay-use-cases-unit.js +658 -0
- package/test/unit/use-cases/schema-use-case-unit.js +101 -0
- package/test/unit/use-cases/this-node-use-cases-unit.js +427 -0
- package/test/unit/use-cases/use-cases-index-unit.js +47 -0
- package/test/unit/util/utils-unit.js +31 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
A mocked version of the adapters library.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class AdaptersMock {
|
|
6
|
+
constructor () {
|
|
7
|
+
this.ipfs = {
|
|
8
|
+
ipfsPeerId: 'fake-id',
|
|
9
|
+
ipfsMultiaddrs: ['addr1', 'addr2'],
|
|
10
|
+
ipfs: {
|
|
11
|
+
pubsub: {
|
|
12
|
+
subscribe: () => {},
|
|
13
|
+
ls: async () => {}
|
|
14
|
+
},
|
|
15
|
+
libp2p: {
|
|
16
|
+
getMultiaddrs: () => [],
|
|
17
|
+
dial: async () => {},
|
|
18
|
+
getPeers: async () => [],
|
|
19
|
+
services: {
|
|
20
|
+
pubsub: {
|
|
21
|
+
publish: async () => {},
|
|
22
|
+
subscribe: async () => {},
|
|
23
|
+
subscriptions: []
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
getPeers: () => {
|
|
29
|
+
},
|
|
30
|
+
connectToPeer: () => {
|
|
31
|
+
},
|
|
32
|
+
disconnectFromPeer: () => {
|
|
33
|
+
},
|
|
34
|
+
disconnectFromMultiaddr: () => {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.bchjs = {}
|
|
39
|
+
|
|
40
|
+
this.type = 'node.js'
|
|
41
|
+
|
|
42
|
+
this.bch = {
|
|
43
|
+
generateBchId: () => {
|
|
44
|
+
return {
|
|
45
|
+
cashAddress: 'cashAddress',
|
|
46
|
+
slpAddress: 'slpAddress',
|
|
47
|
+
publicKey: 'public-key'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
bchjs: {
|
|
51
|
+
Util: {
|
|
52
|
+
sleep: () => {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.pubsub = {
|
|
59
|
+
subscribeToPubsubChannel: () => {
|
|
60
|
+
},
|
|
61
|
+
publishToPubsubChannel: () => {
|
|
62
|
+
},
|
|
63
|
+
messaging: {
|
|
64
|
+
publishToPubsubChannel: () => {
|
|
65
|
+
},
|
|
66
|
+
generateMsgObj: () => {
|
|
67
|
+
},
|
|
68
|
+
generateAckMsg: () => {
|
|
69
|
+
},
|
|
70
|
+
sendMsg: () => {
|
|
71
|
+
},
|
|
72
|
+
sendAck: () => {
|
|
73
|
+
},
|
|
74
|
+
handleIncomingData: () => {
|
|
75
|
+
},
|
|
76
|
+
_checkIfAlreadyProcessed: () => {
|
|
77
|
+
},
|
|
78
|
+
delMsgFromQueue: () => {
|
|
79
|
+
},
|
|
80
|
+
addMsgToQueue: () => {
|
|
81
|
+
},
|
|
82
|
+
resendMsg: () => {
|
|
83
|
+
},
|
|
84
|
+
waitForAck: () => {
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
about: {
|
|
88
|
+
queryAbout: () => {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.encryption = {
|
|
94
|
+
encryptMsg: () => {
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.orbit = {
|
|
99
|
+
createRcvDb: () => {
|
|
100
|
+
return { id: 'fake-orbit-id' }
|
|
101
|
+
},
|
|
102
|
+
connectToPeerDb: () => {
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.log = {
|
|
107
|
+
statusLog: () => {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.gist = {
|
|
112
|
+
getCRList: async () => {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// module.exports = AdaptersMock
|
|
119
|
+
export default AdaptersMock
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Circuit Relays mock */
|
|
2
|
+
const circuitRelays = [
|
|
3
|
+
{
|
|
4
|
+
name: 'ipfs.fullstack.cash',
|
|
5
|
+
multiaddr:
|
|
6
|
+
'/ip4/116.203.193.74/tcp/4001/ipfs/QmNZktxkfScScnHCFSGKELH3YRqdxHQ3Le9rAoRLhZ6vgL',
|
|
7
|
+
connected: true
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
const duplicateRelays = [
|
|
12
|
+
{
|
|
13
|
+
multiaddr:
|
|
14
|
+
'/ip4/139.162.76.54/tcp/5269/ws/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
|
|
15
|
+
connected: true,
|
|
16
|
+
updatedAt: '2021-09-20T15:59:12.961Z',
|
|
17
|
+
ipfsId: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
|
|
18
|
+
isBootstrap: false,
|
|
19
|
+
metrics: { aboutLatency: [] },
|
|
20
|
+
latencyScore: 10000
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
multiaddr:
|
|
24
|
+
'/ip4/157.90.28.11/tcp/4001/p2p/QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
25
|
+
connected: false,
|
|
26
|
+
updatedAt: '2021-09-20T15:58:22.480Z',
|
|
27
|
+
ipfsId: 'QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
28
|
+
isBootstrap: true,
|
|
29
|
+
metrics: { aboutLatency: [] },
|
|
30
|
+
latencyScore: 10000
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
multiaddr:
|
|
34
|
+
'/ip4/157.90.28.11/tcp/4001/p2p/QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
35
|
+
connected: false,
|
|
36
|
+
updatedAt: '2021-09-20T15:58:22.480Z',
|
|
37
|
+
ipfsId: 'QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
38
|
+
isBootstrap: true,
|
|
39
|
+
metrics: { aboutLatency: [] },
|
|
40
|
+
latencyScore: 10000
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
multiaddr:
|
|
44
|
+
'/ip4/157.90.28.11/tcp/4001/p2p/QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
45
|
+
connected: false,
|
|
46
|
+
updatedAt: '2021-09-20T15:58:22.480Z',
|
|
47
|
+
ipfsId: 'QmedLCUDSSvsjfPt9rDm65drNL7Dzu1mk1JCRxu9yuxgLL',
|
|
48
|
+
isBootstrap: true,
|
|
49
|
+
metrics: { aboutLatency: [] },
|
|
50
|
+
latencyScore: 10000
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
multiaddr:
|
|
54
|
+
'/ip4/137.184.13.92/tcp/5668/p2p/Qma4iaNqgCAzA3HqNNEkKZzqWhCMnjt19TEHLu8TKhHhRK',
|
|
55
|
+
connected: true,
|
|
56
|
+
updatedAt: '2021-09-20T15:58:14.963Z',
|
|
57
|
+
ipfsId: 'Qma4iaNqgCAzA3HqNNEkKZzqWhCMnjt19TEHLu8TKhHhRK',
|
|
58
|
+
isBootstrap: true,
|
|
59
|
+
metrics: { aboutLatency: [] },
|
|
60
|
+
latencyScore: 10000
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
export default {
|
|
65
|
+
circuitRelays,
|
|
66
|
+
duplicateRelays
|
|
67
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
A mocked instance of ipfs, for use in unit tests.
|
|
3
|
+
|
|
4
|
+
*/
|
|
5
|
+
const ipfs = {
|
|
6
|
+
id: () => {
|
|
7
|
+
return {
|
|
8
|
+
id: 'myID',
|
|
9
|
+
addresses: ['addr1', 'addr2']
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
swarm: {
|
|
13
|
+
connect: async () => {},
|
|
14
|
+
peers: async () => {
|
|
15
|
+
return []
|
|
16
|
+
},
|
|
17
|
+
disconnect: async () => {}
|
|
18
|
+
},
|
|
19
|
+
pubsub: {
|
|
20
|
+
subscribe: async () => {},
|
|
21
|
+
publish: async () => {}
|
|
22
|
+
},
|
|
23
|
+
config: {
|
|
24
|
+
set: () => {},
|
|
25
|
+
get: () => {},
|
|
26
|
+
getAll: () => {}
|
|
27
|
+
},
|
|
28
|
+
libp2p: {
|
|
29
|
+
peerId: {
|
|
30
|
+
toString: () => 'fake-peerId'
|
|
31
|
+
},
|
|
32
|
+
getMultiaddrs: () => [],
|
|
33
|
+
dial: async () => {},
|
|
34
|
+
getPeers: async () => [],
|
|
35
|
+
services: {
|
|
36
|
+
pubsub: {
|
|
37
|
+
publish: async () => {},
|
|
38
|
+
subscribe: async () => {},
|
|
39
|
+
subscriptions: []
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// module.exports = ipfs
|
|
46
|
+
export default ipfs
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const announceObj = {
|
|
2
|
+
from: 'QmcReHFvNgxFLnLWtVa5SYmeGbmnzBdphKEqPMKJ6XfBh4',
|
|
3
|
+
channel: 'psf-ipfs-coordination-001',
|
|
4
|
+
data: {
|
|
5
|
+
apiName: 'ipfs-coord-announce',
|
|
6
|
+
apiVersion: '1.3.0',
|
|
7
|
+
apiInfo: 'ipfs-hash-to-documentation-to-go-here',
|
|
8
|
+
ipfsId: 'QmcReHFvNgxFLnLWtVa5SYmeGbmnzBdphKEqPMKJ6XfBh4',
|
|
9
|
+
type: 'browser',
|
|
10
|
+
ipfsMultiaddrs: [],
|
|
11
|
+
circuitRelays: [],
|
|
12
|
+
isCircuitRelay: false,
|
|
13
|
+
cryptoAddresses: [],
|
|
14
|
+
encryptPubKey: ''
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const announceObj2 = {
|
|
19
|
+
from: 'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
20
|
+
channel: 'psf-ipfs-coordination-001',
|
|
21
|
+
data: {
|
|
22
|
+
apiName: 'ipfs-coord-announce',
|
|
23
|
+
apiVersion: '1.3.0',
|
|
24
|
+
apiInfo: 'ipfs-hash-to-documentation-to-go-here',
|
|
25
|
+
ipfsId: 'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
26
|
+
type: 'browser',
|
|
27
|
+
ipfsMultiaddrs: [],
|
|
28
|
+
circuitRelays: [],
|
|
29
|
+
isCircuitRelay: false,
|
|
30
|
+
cryptoAddresses: [],
|
|
31
|
+
encryptPubKey: ''
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const swarmPeers = [
|
|
35
|
+
{
|
|
36
|
+
addr:
|
|
37
|
+
'<Multiaddr 049d5a1c0b060fa2a503221220ca9b6cedac4cf9252543e49e94cec725452b8a588641213c67a2841794545b10 - /ip4/157.90.28.11/tcp/4002/p2p/QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsjd>',
|
|
38
|
+
peer: 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsjd'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
addr:
|
|
42
|
+
'<Multiaddr 04934b6409060fa1a503221220c9ab4abc592cae0b1d076c557ce9bc2a9ff5d40a726a683e36fe274afa9122a5 - /ip4/147.75.100.9/tcp/4001/p2p/QmcReHFvNgxFLnLWtVa5SYmeGbmnzBdphKEqPMKJ6XfBh4>',
|
|
43
|
+
peer: 'QmcReHFvNgxFLnLWtVa5SYmeGbmnzBdphKEqPMKJ6XfJh4'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
addr:
|
|
47
|
+
' <Multiaddr 0468838352060fa1a503221220b04a57d40eca138809f139a76b12044333c3740391c9bf1ce9d8e21a79210bfd - /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ>',
|
|
48
|
+
peer: 'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ'
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
// Peers that match with circuit relay address mock id
|
|
52
|
+
const swarmPeers2 = [
|
|
53
|
+
{
|
|
54
|
+
addr:
|
|
55
|
+
' <Multiaddr 0468838352060fa1a503221220b04a57d40eca138809f139a76b12044333c3740391c9bf1ce9d8e21a79210bfd - /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ>',
|
|
56
|
+
peer: 'QmNZktxkfScScnHCFSGKELH3YRqdxHQ3Le9rAoRLhZ6vgL'
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
const mockRelayData = [
|
|
61
|
+
{
|
|
62
|
+
name: 'ipfs.fullstack.cash',
|
|
63
|
+
multiaddr:
|
|
64
|
+
'/ip4/116.203.193.74/tcp/4001/ipfs/QmNZktxkfScScnHCFSGKELH3YRqdxHQ3Le9rAoRLhZ6vgL',
|
|
65
|
+
connected: true
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
export default {
|
|
70
|
+
announceObj,
|
|
71
|
+
announceObj2,
|
|
72
|
+
swarmPeers,
|
|
73
|
+
swarmPeers2,
|
|
74
|
+
mockRelayData
|
|
75
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const mockData = `${'{"apiName":"ipfs-coord","apiVersion":"1.3.0","apiInfo":"ipfs-hash-to-documentation-to-go-here","ipfsId":"QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7","type":"node.js","ipfsMultiaddrs":["/ip4/10.0.0.3/tcp/4002/p2p/QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7","/ip4/127.0.0.1/tcp/4002/p2p/QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7","/ip4/127.0.0.1/tcp/4003/ws/p2p/QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7","/ip4/157.90.20.129/tcp/4002/p2p/QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7"],"circuitRelays":[],"cryptoAddresses":[],"encryptPubKey":""}'}`
|
|
2
|
+
|
|
3
|
+
const mockMsg = {
|
|
4
|
+
from: 'QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7',
|
|
5
|
+
data: Buffer.from(JSON.stringify(mockData)),
|
|
6
|
+
seqno: Buffer.from('test'),
|
|
7
|
+
topicIDs: ['psf-ipfs-coordination-001'],
|
|
8
|
+
signature: Buffer.from('test'),
|
|
9
|
+
key: Buffer.from('test'),
|
|
10
|
+
receivedFrom: 'QmRrUu64cAnPntYiUc7xMunLKZgj1XZT5HmqJNtDMqQcD7'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const aboutRequest = '{"jsonrpc":"2.0","id":"metrics3796","method":"about"}'
|
|
14
|
+
|
|
15
|
+
const aboutResponse = '{"jsonrpc": "2.0", "id": "metrics3796", "result": {"method": "about", "receiver": "12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f", "value": {"ipfsId":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","name":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","type":"node.js","ipfsMultiaddrs":["/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip4/5.161.46.163/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip6/2a01:4ff:f0:f76::1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip6/::1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa"],"isCircuitRelay":true,"circuitRelayInfo":{"ip4":"5.161.46.163","tcpPort":"4001","crDomain":""},"cashAddress":"bitcoincash:qzerrnr5nfdkr3h62cxf0adn4jykjk53zudz4py26e","slpAddress":"simpleledger:qzerrnr5nfdkr3h62cxf0adn4jykjk53zupe7632y8","publicKey":"02e719acbfd3060fa75503ec7af528f5ba67da8a2b9b8e89dbf9b60676740868a0","orbitdbId":"","apiInfo":"You should put an IPFS hash or web URL here to your documentation.","announceJsonLd":{"@context":"https://schema.org/","@type":"WebAPI","name":"ipfs-bch-service-generic","version":"2.0.0","protocol":"bch-wallet","description":"IPFS service providing BCH blockchain access needed by a wallet.","documentation":"https://ipfs-bch-wallet-service.fullstack.cash/","provider":{"@type":"Organization","name":"Permissionless Software Foundation","url":"https://PSFoundation.cash"},"identifier":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa"}}}}'
|
|
16
|
+
|
|
17
|
+
const badId = '{"jsonrpc":"2.0","id":"bad-id","method":"about"}'
|
|
18
|
+
|
|
19
|
+
const msgObj = {
|
|
20
|
+
from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
|
|
21
|
+
channel: '12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f',
|
|
22
|
+
data: {
|
|
23
|
+
timestamp: '2022-03-04T18:19:18.897Z',
|
|
24
|
+
uuid: '311e15f5-e647-488f-8ff5-8a41b254e7c3',
|
|
25
|
+
sender: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
|
|
26
|
+
receiver: '12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f',
|
|
27
|
+
payload: '{"jsonrpc": "2.0", "id": "metrics3796", "result": {"method": "about", "receiver": "12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f", "value": {"ipfsId":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","name":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","type":"node.js","ipfsMultiaddrs":["/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip4/5.161.46.163/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip6/2a01:4ff:f0:f76::1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa","/ip6/::1/tcp/4001/p2p/12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa"],"isCircuitRelay":true,"circuitRelayInfo":{"ip4":"5.161.46.163","tcpPort":"4001","crDomain":""},"cashAddress":"bitcoincash:qzerrnr5nfdkr3h62cxf0adn4jykjk53zudz4py26e","slpAddress":"simpleledger:qzerrnr5nfdkr3h62cxf0adn4jykjk53zupe7632y8","publicKey":"02e719acbfd3060fa75503ec7af528f5ba67da8a2b9b8e89dbf9b60676740868a0","orbitdbId":"","apiInfo":"You should put an IPFS hash or web URL here to your documentation.","announceJsonLd":{"@context":"https://schema.org/","@type":"WebAPI","name":"ipfs-bch-service-generic","version":"2.0.0","protocol":"bch-wallet","description":"IPFS service providing BCH blockchain access needed by a wallet.","documentation":"https://ipfs-bch-wallet-service.fullstack.cash/","provider":{"@type":"Organization","name":"Permissionless Software Foundation","url":"https://PSFoundation.cash"},"identifier":"12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa"}}}}'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
mockMsg,
|
|
33
|
+
aboutRequest,
|
|
34
|
+
aboutResponse,
|
|
35
|
+
badId,
|
|
36
|
+
msgObj
|
|
37
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
'thisNode' is an object that is passed around to a lot of functions. The object
|
|
3
|
+
represents an instance of the IPFS node. This file creates a mock of thisNode
|
|
4
|
+
that can be used for unit tests.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const thisNode = {
|
|
8
|
+
ipfsId: '12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f',
|
|
9
|
+
ipfsMultiaddrs: [
|
|
10
|
+
'/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f',
|
|
11
|
+
'/ip6/::1/tcp/4001/p2p/12D3KooWE6tkdArVpCHG9QN61G1cE7eCq2Q7i4bNx6CJFTDprk9f'
|
|
12
|
+
],
|
|
13
|
+
bchAddr: 'bitcoincash:qpjecejl9n90u9vv7cg7p9qfjk4zjwqus5hff6sfpm',
|
|
14
|
+
slpAddr: 'simpleledger:qpjecejl9n90u9vv7cg7p9qfjk4zjwqus5mjzp9fl9',
|
|
15
|
+
publicKey: '0232ef60e2c545d49d18c95fa7379164693ff6d201221aefea6bee872e4c03be12',
|
|
16
|
+
type: 'node.js',
|
|
17
|
+
peerList: ['12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa'],
|
|
18
|
+
peerData: [
|
|
19
|
+
{
|
|
20
|
+
from: '12D3KooWHS5A6Ey4V8fLWD64jpPn2EKi4r4btGN6FfkNgMTnfqVa',
|
|
21
|
+
channel: 'psf-ipfs-coordination-002',
|
|
22
|
+
data: {
|
|
23
|
+
encryptPubKey: '0232ef60e2c545d49d18c95fa7379164693ff6d201221aefea6bee872e4c03be12'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
relayData: [
|
|
28
|
+
{
|
|
29
|
+
multiaddr: '/ip4/5.161.43.61/tcp/5268/p2p/QmWPfWgbSjPPFpvmS2QH7NPx14DqxMV8eGAUHLcYfyo1St',
|
|
30
|
+
connected: false,
|
|
31
|
+
updatedAt: '2022-03-03T22:01:05.715Z',
|
|
32
|
+
ipfsId: 'QmWPfWgbSjPPFpvmS2QH7NPx14DqxMV8eGAUHLcYfyo1St',
|
|
33
|
+
isBootstrap: false,
|
|
34
|
+
metrics: {},
|
|
35
|
+
latencyScore: 10000
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
multiaddr: '/ip4/88.99.188.196/tcp/5268/p2p/QmXbyd4tWzwhGyyZJ9QJctfJJLq7oAJRs39aqpRXUAbu5j',
|
|
39
|
+
connected: false,
|
|
40
|
+
updatedAt: '2022-03-03T22:01:06.110Z',
|
|
41
|
+
ipfsId: 'QmXbyd4tWzwhGyyZJ9QJctfJJLq7oAJRs39aqpRXUAbu5j',
|
|
42
|
+
isBootstrap: false,
|
|
43
|
+
metrics: {},
|
|
44
|
+
latencyScore: 10000
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
serviceList: [],
|
|
48
|
+
serviceData: [],
|
|
49
|
+
blacklistPeers: [
|
|
50
|
+
'QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
|
51
|
+
'Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6',
|
|
52
|
+
'QmV7gnbW5VTcJ3oyM2Xk1rdFBJ3kTkvxc87UFGsun29STS',
|
|
53
|
+
'QmY7JB6MQXhxHvq7dBDh4HpbH29v4yE9JRadAVpndvzySN',
|
|
54
|
+
'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
55
|
+
'QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
56
|
+
'QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
57
|
+
'QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
58
|
+
'QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
59
|
+
'QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
|
60
|
+
],
|
|
61
|
+
blacklistMultiaddrs: [
|
|
62
|
+
'/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
|
63
|
+
'/dns4/node1.preload.ipfs.io/tcp/443/wss/p2p/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6',
|
|
64
|
+
'/dns4/node2.preload.ipfs.io/tcp/443/wss/p2p/QmV7gnbW5VTcJ3oyM2Xk1rdFBJ3kTkvxc87UFGsun29STS',
|
|
65
|
+
'/dns4/node3.preload.ipfs.io/tcp/443/wss/p2p/QmY7JB6MQXhxHvq7dBDh4HpbH29v4yE9JRadAVpndvzySN',
|
|
66
|
+
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
67
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
68
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
69
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
70
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
71
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
|
|
72
|
+
'/dns4/node0.delegate.ipfs.io/tcp/443/https',
|
|
73
|
+
'/dns4/node1.delegate.ipfs.io/tcp/443/https',
|
|
74
|
+
'/dns4/node2.delegate.ipfs.io/tcp/443/https',
|
|
75
|
+
'/dns4/node3.delegate.ipfs.io/tcp/443/https'
|
|
76
|
+
],
|
|
77
|
+
schema: {},
|
|
78
|
+
useCases: {}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// module.exports = thisNode
|
|
82
|
+
export default thisNode
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Mocked version of the Use Cases library.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class UseCasesMock {
|
|
6
|
+
constructor () {
|
|
7
|
+
this.thisNode = {
|
|
8
|
+
refreshPeerConnections: () => {},
|
|
9
|
+
enforceBlacklist: () => {},
|
|
10
|
+
enforceWhitelist: () => {}
|
|
11
|
+
}
|
|
12
|
+
this.relays = {
|
|
13
|
+
connectToCRs: () => {},
|
|
14
|
+
addRelay: () => {},
|
|
15
|
+
measureRelays: () => {},
|
|
16
|
+
sortRelays: obj => obj,
|
|
17
|
+
removeDuplicates: () => {}
|
|
18
|
+
}
|
|
19
|
+
this.pubsub = {}
|
|
20
|
+
this.peer = {}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default UseCasesMock
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for the bch-lib library.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// npm libraries
|
|
6
|
+
import { assert } from 'chai'
|
|
7
|
+
import sinon from 'sinon'
|
|
8
|
+
import SlpWallet from 'minimal-slp-wallet'
|
|
9
|
+
|
|
10
|
+
// local libraries
|
|
11
|
+
import BchLib from '../../../lib/adapters/bch-adapter.js'
|
|
12
|
+
|
|
13
|
+
describe('#bch-adapter', () => {
|
|
14
|
+
let sandbox
|
|
15
|
+
let uut
|
|
16
|
+
let wallet
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
// Restore the sandbox before each test.
|
|
20
|
+
sandbox = sinon.createSandbox()
|
|
21
|
+
|
|
22
|
+
wallet = new SlpWallet()
|
|
23
|
+
await wallet.walletInfoPromise
|
|
24
|
+
|
|
25
|
+
uut = new BchLib({ wallet })
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => sandbox.restore())
|
|
29
|
+
|
|
30
|
+
describe('#constructor', () => {
|
|
31
|
+
it('should throw an error if minimal-slp-wallet instance is not passed in', () => {
|
|
32
|
+
try {
|
|
33
|
+
uut = new BchLib({})
|
|
34
|
+
} catch (err) {
|
|
35
|
+
assert.include(
|
|
36
|
+
err.message,
|
|
37
|
+
'An instance of minimal-slp-wallet must be passed when instantiating the BCH adapter library.'
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
describe('#generateBchId', () => {
|
|
44
|
+
it('should generate a new BCH ID if mnemonic is not given', async () => {
|
|
45
|
+
const result = await uut.generateBchId()
|
|
46
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
47
|
+
|
|
48
|
+
assert.property(result, 'cashAddress')
|
|
49
|
+
assert.property(result, 'slpAddress')
|
|
50
|
+
assert.property(result, 'publicKey')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should catch and throw an error', async () => {
|
|
54
|
+
try {
|
|
55
|
+
sandbox
|
|
56
|
+
.stub(uut.bchjs.Mnemonic, 'toSeed')
|
|
57
|
+
.rejects(new Error('test error'))
|
|
58
|
+
|
|
59
|
+
await uut.generateBchId()
|
|
60
|
+
|
|
61
|
+
assert.fail('Unexpected code path. Error was expected to be thrown.')
|
|
62
|
+
} catch (err) {
|
|
63
|
+
// console.log(err)
|
|
64
|
+
assert.include(err.message, 'test error')
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
describe('#generatePrivateKey', () => {
|
|
70
|
+
it('should generate a private key', async () => {
|
|
71
|
+
const result = await uut.generatePrivateKey()
|
|
72
|
+
console.log('result: ', result)
|
|
73
|
+
|
|
74
|
+
// The private key shoul be a string.
|
|
75
|
+
assert.isString(result)
|
|
76
|
+
|
|
77
|
+
// It shoul be a WIF that starts with a K or L
|
|
78
|
+
// assert.equal(result[0], 'K' || 'L')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('should catch and throw an error', async () => {
|
|
82
|
+
try {
|
|
83
|
+
sandbox
|
|
84
|
+
.stub(uut.bchjs.Mnemonic, 'toSeed')
|
|
85
|
+
.rejects(new Error('test error'))
|
|
86
|
+
|
|
87
|
+
await uut.generatePrivateKey()
|
|
88
|
+
|
|
89
|
+
assert.fail('Unexpected code path. Error was expected to be thrown.')
|
|
90
|
+
} catch (err) {
|
|
91
|
+
// console.log(err)
|
|
92
|
+
assert.include(err.message, 'test error')
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
})
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for the encryption adapter library.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// npm libraries
|
|
6
|
+
import { assert } from 'chai'
|
|
7
|
+
import sinon from 'sinon'
|
|
8
|
+
import SlpWallet from 'minimal-slp-wallet'
|
|
9
|
+
|
|
10
|
+
// local libraries
|
|
11
|
+
import EncryptionAdapter from '../../../lib/adapters/encryption-adapter.js'
|
|
12
|
+
import BchAdapter from '../../../lib/adapters/bch-adapter.js'
|
|
13
|
+
|
|
14
|
+
describe('#Adapters - Encryption', () => {
|
|
15
|
+
let uut
|
|
16
|
+
let sandbox
|
|
17
|
+
let wallet
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
// Restore the sandbox before each test.
|
|
21
|
+
sandbox = sinon.createSandbox()
|
|
22
|
+
|
|
23
|
+
wallet = new SlpWallet()
|
|
24
|
+
await wallet.walletInfoPromise
|
|
25
|
+
|
|
26
|
+
const bch = new BchAdapter({ wallet })
|
|
27
|
+
|
|
28
|
+
// Instantiate the library under test. Must instantiate dependencies first.
|
|
29
|
+
uut = new EncryptionAdapter({ bch })
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
afterEach(() => sandbox.restore())
|
|
33
|
+
|
|
34
|
+
describe('#constructor', () => {
|
|
35
|
+
it('should throw an error if bch adapter is not included', () => {
|
|
36
|
+
try {
|
|
37
|
+
uut = new EncryptionAdapter()
|
|
38
|
+
|
|
39
|
+
assert.fail('Unexpected code path')
|
|
40
|
+
} catch (err) {
|
|
41
|
+
assert.include(
|
|
42
|
+
err.message,
|
|
43
|
+
'Must pass in an instance of bch Adapter when instantiating the encryption Adapter library.'
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe('#decryptMsg', () => {
|
|
50
|
+
it('should decrypt a message', async () => {
|
|
51
|
+
// Mock dependencies
|
|
52
|
+
sandbox
|
|
53
|
+
.stub(uut.bchEncrypt.encryption, 'decryptFile')
|
|
54
|
+
.resolves('decryptedMsg')
|
|
55
|
+
|
|
56
|
+
const result = await uut.decryptMsg('F6')
|
|
57
|
+
// console.log('result: ', result)
|
|
58
|
+
|
|
59
|
+
assert.isOk(result)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should handle BAD MAC error messages', async () => {
|
|
63
|
+
try {
|
|
64
|
+
// Force a BAD MAC error
|
|
65
|
+
sandbox
|
|
66
|
+
.stub(uut.bchEncrypt.encryption, 'decryptFile')
|
|
67
|
+
.rejects(new Error('Bad MAC'))
|
|
68
|
+
|
|
69
|
+
await uut.decryptMsg('F6')
|
|
70
|
+
|
|
71
|
+
assert.fail('Unexpected code path')
|
|
72
|
+
} catch (err) {
|
|
73
|
+
assert.include(err.message, 'Bad MAC. Could not decrypt message.')
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should catch and throw an error', async () => {
|
|
78
|
+
try {
|
|
79
|
+
// Force an error
|
|
80
|
+
sandbox
|
|
81
|
+
.stub(uut.bchEncrypt.encryption, 'decryptFile')
|
|
82
|
+
.rejects(new Error('test error'))
|
|
83
|
+
|
|
84
|
+
await uut.decryptMsg('F6')
|
|
85
|
+
|
|
86
|
+
assert.fail('Unexpected code path')
|
|
87
|
+
} catch (err) {
|
|
88
|
+
assert.include(err.message, 'test error')
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('#encryptMsg', () => {
|
|
94
|
+
it('should catch and throw errors', async () => {
|
|
95
|
+
try {
|
|
96
|
+
const peer = {
|
|
97
|
+
data: {
|
|
98
|
+
encryptionKey: 'abc123'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await uut.encryptMsg(peer, 'testMsg')
|
|
103
|
+
// console.log('result: ', result)
|
|
104
|
+
|
|
105
|
+
assert.fail('Unexpected code path')
|
|
106
|
+
} catch (err) {
|
|
107
|
+
assert.include(err.message, 'pubkey must be a hex string')
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('should encrypt a string', async () => {
|
|
112
|
+
// Mock dependencies
|
|
113
|
+
sandbox
|
|
114
|
+
.stub(uut.bchEncrypt.encryption, 'encryptFile')
|
|
115
|
+
.resolves('encryptedMsg')
|
|
116
|
+
|
|
117
|
+
const peer = {
|
|
118
|
+
data: {
|
|
119
|
+
encryptionKey: 'abc123'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const result = await uut.encryptMsg(peer, 'testMsg')
|
|
124
|
+
// console.log('result: ', result)
|
|
125
|
+
|
|
126
|
+
assert.equal(result, 'encryptedMsg')
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
})
|