@bsv/sdk 1.2.20 → 1.2.22
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/dist/cjs/package.json +3 -3
- package/dist/cjs/src/auth/Peer.js +536 -0
- package/dist/cjs/src/auth/Peer.js.map +1 -0
- package/dist/cjs/src/auth/SessionManager.js +66 -0
- package/dist/cjs/src/auth/SessionManager.js.map +1 -0
- package/dist/cjs/src/auth/{Certificate.js → certificates/Certificate.js} +22 -26
- package/dist/cjs/src/auth/certificates/Certificate.js.map +1 -0
- package/dist/cjs/src/auth/certificates/MasterCertificate.js +79 -0
- package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -0
- package/dist/cjs/src/auth/certificates/VerifiableCertificate.js +49 -0
- package/dist/cjs/src/auth/certificates/VerifiableCertificate.js.map +1 -0
- package/dist/cjs/src/auth/certificates/index.js +25 -0
- package/dist/cjs/src/auth/certificates/index.js.map +1 -0
- package/dist/cjs/src/auth/clients/AuthFetch.js +411 -0
- package/dist/cjs/src/auth/clients/AuthFetch.js.map +1 -0
- package/dist/cjs/src/auth/clients/index.js +18 -0
- package/dist/cjs/src/auth/clients/index.js.map +1 -0
- package/dist/cjs/src/auth/index.js +20 -5
- package/dist/cjs/src/auth/index.js.map +1 -1
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +259 -0
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -0
- package/dist/cjs/src/auth/transports/index.js +18 -0
- package/dist/cjs/src/auth/transports/index.js.map +1 -0
- package/dist/cjs/src/auth/types.js +3 -0
- package/dist/cjs/src/auth/types.js.map +1 -0
- package/dist/cjs/src/auth/utils/certificateHelpers.js +51 -0
- package/dist/cjs/src/auth/utils/certificateHelpers.js.map +1 -0
- package/dist/cjs/src/auth/utils/createNonce.js +19 -0
- package/dist/cjs/src/auth/utils/createNonce.js.map +1 -0
- package/dist/cjs/src/auth/utils/getVerifiableCertificates.js +31 -0
- package/dist/cjs/src/auth/utils/getVerifiableCertificates.js.map +1 -0
- package/dist/cjs/src/auth/utils/index.js +22 -0
- package/dist/cjs/src/auth/utils/index.js.map +1 -0
- package/dist/cjs/src/auth/utils/validateCertificates.js +42 -0
- package/dist/cjs/src/auth/utils/validateCertificates.js.map +1 -0
- package/dist/cjs/src/auth/utils/verifyNonce.js +27 -0
- package/dist/cjs/src/auth/utils/verifyNonce.js.map +1 -0
- package/dist/cjs/src/primitives/Point.js +1 -1
- package/dist/cjs/src/primitives/Point.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js +148 -148
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/Peer.js +533 -0
- package/dist/esm/src/auth/Peer.js.map +1 -0
- package/dist/esm/src/auth/SessionManager.js +63 -0
- package/dist/esm/src/auth/SessionManager.js.map +1 -0
- package/dist/esm/src/auth/{Certificate.js → certificates/Certificate.js} +1 -2
- package/dist/esm/src/auth/certificates/Certificate.js.map +1 -0
- package/dist/esm/src/auth/certificates/MasterCertificate.js +73 -0
- package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -0
- package/dist/esm/src/auth/certificates/VerifiableCertificate.js +44 -0
- package/dist/esm/src/auth/certificates/VerifiableCertificate.js.map +1 -0
- package/dist/esm/src/auth/certificates/index.js +4 -0
- package/dist/esm/src/auth/certificates/index.js.map +1 -0
- package/dist/esm/src/auth/clients/AuthFetch.js +409 -0
- package/dist/esm/src/auth/clients/AuthFetch.js.map +1 -0
- package/dist/esm/src/auth/clients/index.js +2 -0
- package/dist/esm/src/auth/clients/index.js.map +1 -0
- package/dist/esm/src/auth/index.js +7 -1
- package/dist/esm/src/auth/index.js.map +1 -1
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +258 -0
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -0
- package/dist/esm/src/auth/transports/index.js +2 -0
- package/dist/esm/src/auth/transports/index.js.map +1 -0
- package/dist/esm/src/auth/types.js +2 -0
- package/dist/esm/src/auth/types.js.map +1 -0
- package/dist/esm/src/auth/utils/certificateHelpers.js +47 -0
- package/dist/esm/src/auth/utils/certificateHelpers.js.map +1 -0
- package/dist/esm/src/auth/utils/createNonce.js +16 -0
- package/dist/esm/src/auth/utils/createNonce.js.map +1 -0
- package/dist/esm/src/auth/utils/getVerifiableCertificates.js +27 -0
- package/dist/esm/src/auth/utils/getVerifiableCertificates.js.map +1 -0
- package/dist/esm/src/auth/utils/index.js +6 -0
- package/dist/esm/src/auth/utils/index.js.map +1 -0
- package/dist/esm/src/auth/utils/validateCertificates.js +38 -0
- package/dist/esm/src/auth/utils/validateCertificates.js.map +1 -0
- package/dist/esm/src/auth/utils/verifyNonce.js +24 -0
- package/dist/esm/src/auth/utils/verifyNonce.js.map +1 -0
- package/dist/esm/src/primitives/Point.js +1 -1
- package/dist/esm/src/primitives/Point.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/Peer.d.ts +193 -0
- package/dist/types/src/auth/Peer.d.ts.map +1 -0
- package/dist/types/src/auth/SessionManager.d.ts +42 -0
- package/dist/types/src/auth/SessionManager.d.ts.map +1 -0
- package/dist/types/src/auth/{Certificate.d.ts → certificates/Certificate.d.ts} +1 -1
- package/dist/types/src/auth/certificates/Certificate.d.ts.map +1 -0
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts +38 -0
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts.map +1 -0
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts +26 -0
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts.map +1 -0
- package/dist/types/src/auth/certificates/index.d.ts +4 -0
- package/dist/types/src/auth/certificates/index.d.ts.map +1 -0
- package/dist/types/src/auth/clients/AuthFetch.d.ts +87 -0
- package/dist/types/src/auth/clients/AuthFetch.d.ts.map +1 -0
- package/dist/types/src/auth/clients/index.d.ts +2 -0
- package/dist/types/src/auth/clients/index.d.ts.map +1 -0
- package/dist/types/src/auth/index.d.ts +7 -1
- package/dist/types/src/auth/index.d.ts.map +1 -1
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts +51 -0
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts.map +1 -0
- package/dist/types/src/auth/transports/index.d.ts +2 -0
- package/dist/types/src/auth/transports/index.d.ts.map +1 -0
- package/dist/types/src/auth/types.d.ts +31 -0
- package/dist/types/src/auth/types.d.ts.map +1 -0
- package/dist/types/src/auth/utils/certificateHelpers.d.ts +26 -0
- package/dist/types/src/auth/utils/certificateHelpers.d.ts.map +1 -0
- package/dist/types/src/auth/utils/createNonce.d.ts +8 -0
- package/dist/types/src/auth/utils/createNonce.d.ts.map +1 -0
- package/dist/types/src/auth/utils/getVerifiableCertificates.d.ts +13 -0
- package/dist/types/src/auth/utils/getVerifiableCertificates.d.ts.map +1 -0
- package/dist/types/src/auth/utils/index.d.ts +6 -0
- package/dist/types/src/auth/utils/index.d.ts.map +1 -0
- package/dist/types/src/auth/utils/validateCertificates.d.ts +12 -0
- package/dist/types/src/auth/utils/validateCertificates.d.ts.map +1 -0
- package/dist/types/src/auth/utils/verifyNonce.d.ts +9 -0
- package/dist/types/src/auth/utils/verifyNonce.d.ts.map +1 -0
- package/dist/types/src/primitives/Point.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/README.md +1 -0
- package/docs/auth.md +1193 -0
- package/package.json +13 -3
- package/src/auth/Peer.ts +600 -0
- package/src/auth/SessionManager.ts +71 -0
- package/src/auth/__tests/Peer.test.ts +599 -0
- package/src/auth/__tests/SessionManager.test.ts +87 -0
- package/src/auth/{Certificate.ts → certificates/Certificate.ts} +15 -8
- package/src/auth/certificates/MasterCertificate.ts +106 -0
- package/src/auth/certificates/VerifiableCertificate.ts +73 -0
- package/src/auth/certificates/__tests/Certificate.test.ts +282 -0
- package/src/auth/certificates/index.ts +3 -0
- package/src/auth/clients/AuthFetch.ts +482 -0
- package/src/auth/clients/index.ts +1 -0
- package/src/auth/index.ts +7 -1
- package/src/auth/transports/SimplifiedFetchTransport.ts +288 -0
- package/src/auth/transports/index.ts +1 -0
- package/src/auth/types.ts +41 -0
- package/src/auth/utils/__tests/cryptononce.test.ts +84 -0
- package/src/auth/utils/__tests/getVerifiableCertificates.test.ts +126 -0
- package/src/auth/utils/__tests/validateCertificates.test.ts +142 -0
- package/src/auth/utils/certificateHelpers.ts +86 -0
- package/src/auth/utils/createNonce.ts +16 -0
- package/src/auth/utils/getVerifiableCertificates.ts +40 -0
- package/src/auth/utils/index.ts +5 -0
- package/src/auth/utils/validateCertificates.ts +54 -0
- package/src/auth/utils/verifyNonce.ts +27 -0
- package/src/primitives/Point.ts +59 -59
- package/src/wallet/substrates/WalletWireProcessor.ts +1 -1
- package/src/wallet/substrates/WalletWireTransceiver.ts +1 -1
- package/dist/cjs/src/auth/Certificate.js.map +0 -1
- package/dist/esm/src/auth/Certificate.js.map +0 -1
- package/dist/types/src/auth/Certificate.d.ts.map +0 -1
- package/src/auth/__tests/Certificate.test.ts +0 -282
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PeerSession } from './types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Manages sessions for peers, allowing sessions to be added, retrieved, updated, and removed
|
|
5
|
+
* by relevant identifiers (sessionNonce and peerIdentityKey).
|
|
6
|
+
*/
|
|
7
|
+
export class SessionManager {
|
|
8
|
+
private readonly identifierToSession: Map<string, PeerSession>
|
|
9
|
+
|
|
10
|
+
constructor () {
|
|
11
|
+
this.identifierToSession = new Map<string, PeerSession>()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Adds a session to the manager, associating it with relevant identifiers for retrieval.
|
|
16
|
+
*
|
|
17
|
+
* @param {PeerSession} session - The peer session to add.
|
|
18
|
+
*/
|
|
19
|
+
addSession (session: PeerSession): void {
|
|
20
|
+
if (!session.sessionNonce && !session.peerIdentityKey) {
|
|
21
|
+
throw new Error('Invalid session: at least one of sessionNonce or peerIdentityKey is required.')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (session.sessionNonce) {
|
|
25
|
+
this.identifierToSession.set(session.sessionNonce, session)
|
|
26
|
+
}
|
|
27
|
+
if (session.peerIdentityKey) {
|
|
28
|
+
this.identifierToSession.set(session.peerIdentityKey, session)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Updates a session in the manager, ensuring that all identifiers are correctly associated.
|
|
34
|
+
*
|
|
35
|
+
* @param {PeerSession} session - The peer session to update.
|
|
36
|
+
*/
|
|
37
|
+
updateSession (session: PeerSession): void {
|
|
38
|
+
this.removeSession(session)
|
|
39
|
+
this.addSession(session)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Retrieves a session based on a given identifier.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} identifier - The identifier for the session (sessionNonce or peerIdentityKey).
|
|
46
|
+
* @returns {PeerSession | undefined} - The matching peer session, or undefined if not found.
|
|
47
|
+
*/
|
|
48
|
+
getSession (identifier: string): PeerSession | undefined {
|
|
49
|
+
return this.identifierToSession.get(identifier)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Removes a session from the manager by clearing all associated identifiers.
|
|
54
|
+
*
|
|
55
|
+
* @param {PeerSession} session - The peer session to remove.
|
|
56
|
+
*/
|
|
57
|
+
removeSession (session: PeerSession): void {
|
|
58
|
+
this.identifierToSession.delete(session.sessionNonce)
|
|
59
|
+
this.identifierToSession.delete(session.peerIdentityKey)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Checks if a session exists based on a given identifier.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} identifier - The identifier to check.
|
|
66
|
+
* @returns {boolean} - True if the session exists, false otherwise.
|
|
67
|
+
*/
|
|
68
|
+
hasSession (identifier: string): boolean {
|
|
69
|
+
return this.identifierToSession.has(identifier)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
import { Peer } from "../../../dist/cjs/src/auth/Peer.js"
|
|
2
|
+
import { AuthMessage, Transport } from "../../../dist/cjs/src/auth/types.js"
|
|
3
|
+
import { jest } from '@jest/globals'
|
|
4
|
+
import { Wallet } from "../../../dist/cjs/src/wallet/Wallet.interfaces.js"
|
|
5
|
+
import { ProtoWallet } from '../../../dist/cjs/src/wallet/index.js'
|
|
6
|
+
import { Utils, PrivateKey, SymmetricKey } from '../../../dist/cjs/src/primitives/index.js'
|
|
7
|
+
import { VerifiableCertificate, } from "../../../dist/cjs/src/auth/certificates/VerifiableCertificate.js"
|
|
8
|
+
import { MasterCertificate } from '../../../dist/cjs/src/auth/certificates/MasterCertificate.js'
|
|
9
|
+
import { getVerifiableCertificates } from '../../../dist/cjs/src/auth/utils/getVerifiableCertificates.js'
|
|
10
|
+
jest.mock('../../../dist/cjs/src/auth/utils/getVerifiableCertificates.js')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A helper function to decrypt a VerifiableCertificate's fields using the provided wallets.
|
|
14
|
+
*/
|
|
15
|
+
async function decryptCertificateFields(
|
|
16
|
+
cert: VerifiableCertificate,
|
|
17
|
+
localWallet: Wallet,
|
|
18
|
+
counterpartyWallet: Wallet
|
|
19
|
+
): Promise<Record<string, string>> {
|
|
20
|
+
const entries = await Promise.all(
|
|
21
|
+
Object.entries(cert.keyring).map(async ([fieldName, encryptedKey]) => {
|
|
22
|
+
// Decrypt the per-field symmetric key
|
|
23
|
+
const { plaintext: masterFieldKey } = await localWallet.decrypt({
|
|
24
|
+
ciphertext: Utils.toArray(encryptedKey, 'base64'),
|
|
25
|
+
protocolID: [2, 'certificate field encryption'],
|
|
26
|
+
keyID: `${cert.serialNumber} ${fieldName}`,
|
|
27
|
+
counterparty: (await counterpartyWallet.getPublicKey({ identityKey: true })).publicKey,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Decrypt the actual field contents using the decrypted symmetric key
|
|
31
|
+
try {
|
|
32
|
+
const decryptedData = new SymmetricKey(masterFieldKey).decrypt(
|
|
33
|
+
Utils.toArray(cert.fields[fieldName], 'base64')
|
|
34
|
+
)
|
|
35
|
+
return { key: fieldName, value: Utils.toUTF8(decryptedData as number[]) }
|
|
36
|
+
} catch (_) {
|
|
37
|
+
throw new Error(`Decryption of the "${fieldName}" field with its revelation key failed.`)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return entries.reduce((acc, { key, value }) => {
|
|
43
|
+
acc[key] = value
|
|
44
|
+
return acc
|
|
45
|
+
}, {} as Record<string, string>)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class LocalTransport implements Transport {
|
|
49
|
+
private peerTransport?: LocalTransport
|
|
50
|
+
private onDataCallback?: (message: AuthMessage) => void
|
|
51
|
+
|
|
52
|
+
connect(peerTransport: LocalTransport): void {
|
|
53
|
+
this.peerTransport = peerTransport
|
|
54
|
+
peerTransport.peerTransport = this
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async send(message: AuthMessage): Promise<void> {
|
|
58
|
+
if (this.peerTransport && this.peerTransport.onDataCallback) {
|
|
59
|
+
// Simulate message delivery by calling the onData callback of the peer
|
|
60
|
+
this.peerTransport.onDataCallback(message)
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error("Peer transport is not connected or not listening for data.")
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async onData(callback: (message: AuthMessage) => Promise<void>): Promise<void> {
|
|
67
|
+
this.onDataCallback = callback
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe('Peer class mutual authentication and certificate exchange', () => {
|
|
72
|
+
let walletA: Wallet, walletB: Wallet
|
|
73
|
+
let transportA: LocalTransport, transportB: LocalTransport
|
|
74
|
+
let alice: Peer, bob: Peer
|
|
75
|
+
let certificatesReceivedByAlice: VerifiableCertificate[] | undefined
|
|
76
|
+
let certificatesReceivedByBob: VerifiableCertificate[] | undefined
|
|
77
|
+
|
|
78
|
+
const certificateType = Utils.toBase64(new Array(32).fill(1))
|
|
79
|
+
const certificateSerialNumber = Utils.toBase64(new Array(32).fill(2))
|
|
80
|
+
const certifierPrivateKey = PrivateKey.fromRandom()
|
|
81
|
+
const certifierPublicKey = certifierPrivateKey.toPublicKey().toString()
|
|
82
|
+
const certificatesToRequest = {
|
|
83
|
+
certifiers: [certifierPublicKey],
|
|
84
|
+
types: { [certificateType]: ['name', 'email'] }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const aliceFields = { name: 'Alice', email: 'alice@example.com', libraryCardNumber: 'A123456' }
|
|
88
|
+
const bobFields = { name: 'Bob', email: 'bob@example.com', libraryCardNumber: 'B654321' }
|
|
89
|
+
|
|
90
|
+
async function createMasterCertificate(wallet: Wallet, fields: Record<string, string>) {
|
|
91
|
+
const certificateFields: Record<string, string> = {}
|
|
92
|
+
const masterKeyring: Record<string, string> = {}
|
|
93
|
+
|
|
94
|
+
for (const fieldName in fields) {
|
|
95
|
+
const fieldSymmetricKey = SymmetricKey.fromRandom()
|
|
96
|
+
const encryptedFieldValue = fieldSymmetricKey.encrypt(Utils.toArray(fields[fieldName], 'utf8'))
|
|
97
|
+
certificateFields[fieldName] = Utils.toBase64(encryptedFieldValue as number[])
|
|
98
|
+
|
|
99
|
+
const encryptedFieldKey = await wallet.encrypt({
|
|
100
|
+
plaintext: fieldSymmetricKey.toArray(),
|
|
101
|
+
protocolID: [2, 'certificate field encryption'],
|
|
102
|
+
keyID: `${certificateSerialNumber} ${fieldName}`,
|
|
103
|
+
counterparty: 'self'
|
|
104
|
+
})
|
|
105
|
+
masterKeyring[fieldName] = Utils.toBase64(encryptedFieldKey.ciphertext)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return new MasterCertificate(
|
|
109
|
+
certificateType,
|
|
110
|
+
certificateSerialNumber,
|
|
111
|
+
(await wallet.getPublicKey({ identityKey: true })).publicKey,
|
|
112
|
+
certifierPublicKey,
|
|
113
|
+
'revocationOutpoint',
|
|
114
|
+
certificateFields,
|
|
115
|
+
masterKeyring
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function createVerifiableCertificate(
|
|
120
|
+
masterCertificate: MasterCertificate,
|
|
121
|
+
wallet: Wallet,
|
|
122
|
+
verifierIdentityKey: string,
|
|
123
|
+
fieldsToReveal: string[]
|
|
124
|
+
): Promise<VerifiableCertificate> {
|
|
125
|
+
const certifierWallet = new ProtoWallet(certifierPrivateKey)
|
|
126
|
+
await masterCertificate.sign(certifierWallet)
|
|
127
|
+
|
|
128
|
+
const keyringForVerifier = await masterCertificate.createKeyringForVerifier(wallet, verifierIdentityKey, fieldsToReveal)
|
|
129
|
+
return new VerifiableCertificate(
|
|
130
|
+
masterCertificate.type,
|
|
131
|
+
masterCertificate.serialNumber,
|
|
132
|
+
masterCertificate.subject,
|
|
133
|
+
masterCertificate.certifier,
|
|
134
|
+
masterCertificate.revocationOutpoint,
|
|
135
|
+
masterCertificate.fields,
|
|
136
|
+
masterCertificate.signature,
|
|
137
|
+
keyringForVerifier
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function setupPeers(
|
|
142
|
+
aliceRequests: boolean,
|
|
143
|
+
bobRequests: boolean,
|
|
144
|
+
options: {
|
|
145
|
+
aliceCertsToRequest?: typeof certificatesToRequest,
|
|
146
|
+
bobCertsToRequest?: typeof certificatesToRequest
|
|
147
|
+
} = {}
|
|
148
|
+
) {
|
|
149
|
+
const { aliceCertsToRequest = certificatesToRequest, bobCertsToRequest = certificatesToRequest } = options
|
|
150
|
+
|
|
151
|
+
alice = new Peer(walletA, transportA, aliceRequests ? aliceCertsToRequest : undefined)
|
|
152
|
+
bob = new Peer(walletB, transportB, bobRequests ? bobCertsToRequest : undefined)
|
|
153
|
+
|
|
154
|
+
const aliceReceivedCertificates = new Promise<void>((resolve) => {
|
|
155
|
+
alice.listenForCertificatesReceived((senderPublicKey, certificates) => {
|
|
156
|
+
certificatesReceivedByAlice = certificates
|
|
157
|
+
resolve()
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
const bobReceivedCertificates = new Promise<void>((resolve) => {
|
|
162
|
+
bob.listenForCertificatesReceived((senderPublicKey, certificates) => {
|
|
163
|
+
certificatesReceivedByBob = certificates
|
|
164
|
+
resolve()
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return { aliceReceivedCertificates, bobReceivedCertificates }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function mockGetVerifiableCertificates(
|
|
172
|
+
aliceCertificate: VerifiableCertificate | undefined,
|
|
173
|
+
bobCertificate: VerifiableCertificate | undefined,
|
|
174
|
+
alicePubKey: string,
|
|
175
|
+
bobPubKey: string
|
|
176
|
+
) {
|
|
177
|
+
(getVerifiableCertificates as jest.Mock).mockImplementation((wallet, _, verifierIdentityKey) => {
|
|
178
|
+
if (wallet === walletA && verifierIdentityKey === bobPubKey) {
|
|
179
|
+
return aliceCertificate ? Promise.resolve([aliceCertificate]) : Promise.resolve([])
|
|
180
|
+
} else if (wallet === walletB && verifierIdentityKey === alicePubKey) {
|
|
181
|
+
return bobCertificate ? Promise.resolve([bobCertificate]) : Promise.resolve([])
|
|
182
|
+
}
|
|
183
|
+
return Promise.resolve([])
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
beforeEach(async () => {
|
|
188
|
+
transportA = new LocalTransport()
|
|
189
|
+
transportB = new LocalTransport()
|
|
190
|
+
transportA.connect(transportB)
|
|
191
|
+
|
|
192
|
+
certificatesReceivedByAlice = []
|
|
193
|
+
certificatesReceivedByBob = []
|
|
194
|
+
|
|
195
|
+
walletA = new ProtoWallet(PrivateKey.fromRandom())
|
|
196
|
+
walletB = new ProtoWallet(PrivateKey.fromRandom())
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('Neither Alice nor Bob request certificates, mutual authentication completes successfully', async () => {
|
|
200
|
+
const { aliceReceivedCertificates, bobReceivedCertificates } = setupPeers(false, false)
|
|
201
|
+
|
|
202
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
203
|
+
bob.listenForGeneralMessages(async (senderPublicKey, payload) => {
|
|
204
|
+
console.log('Bob received message:', Utils.toUTF8(payload))
|
|
205
|
+
await bob.toPeer(Utils.toArray('Hello Alice!'), senderPublicKey)
|
|
206
|
+
resolve()
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
const aliceReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
210
|
+
alice.listenForGeneralMessages(async (senderPublicKey, payload) => {
|
|
211
|
+
console.log('Alice received message:', Utils.toUTF8(payload))
|
|
212
|
+
resolve()
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
await alice.toPeer(Utils.toArray('Hello Bob!'))
|
|
217
|
+
await bobReceivedGeneralMessage
|
|
218
|
+
await aliceReceivedGeneralMessage
|
|
219
|
+
|
|
220
|
+
expect(certificatesReceivedByAlice).toEqual([])
|
|
221
|
+
expect(certificatesReceivedByBob).toEqual([])
|
|
222
|
+
}, 15000)
|
|
223
|
+
|
|
224
|
+
it('Bob requests certificates from Alice, Alice does not request any from Bob', async () => {
|
|
225
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
226
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
227
|
+
|
|
228
|
+
const aliceMasterCertificate = await createMasterCertificate(walletA, aliceFields)
|
|
229
|
+
const aliceVerifiableCertificate = await createVerifiableCertificate(
|
|
230
|
+
aliceMasterCertificate,
|
|
231
|
+
walletA,
|
|
232
|
+
bobPubKey,
|
|
233
|
+
certificatesToRequest.types[certificateType]
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
const { bobReceivedCertificates } = setupPeers(false, true)
|
|
237
|
+
mockGetVerifiableCertificates(aliceVerifiableCertificate, undefined, alicePubKey, bobPubKey)
|
|
238
|
+
|
|
239
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
240
|
+
bob.listenForGeneralMessages(async (senderPublicKey, payload) => {
|
|
241
|
+
await bobReceivedCertificates
|
|
242
|
+
if (certificatesReceivedByBob?.length !== 0) {
|
|
243
|
+
certificatesReceivedByBob?.forEach(async cert => {
|
|
244
|
+
// Decrypt to ensure it has the correct fields
|
|
245
|
+
const decryptedFields = await decryptCertificateFields(cert, walletB, walletA)
|
|
246
|
+
if (cert.certifier !== 'bob') {
|
|
247
|
+
console.log('Bob accepted the message:', Utils.toUTF8(payload))
|
|
248
|
+
console.log('Decrypted fields:', decryptedFields)
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
resolve()
|
|
253
|
+
})
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
await alice.toPeer(Utils.toArray('Hello Bob!'))
|
|
257
|
+
await bobReceivedGeneralMessage
|
|
258
|
+
|
|
259
|
+
expect(certificatesReceivedByAlice).toEqual([])
|
|
260
|
+
expect(certificatesReceivedByBob).toEqual([aliceVerifiableCertificate])
|
|
261
|
+
}, 15000)
|
|
262
|
+
|
|
263
|
+
it('Alice requests Bob to present his library card before lending him a book', async () => {
|
|
264
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
265
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
266
|
+
|
|
267
|
+
// Bob's certificate includes his library card number
|
|
268
|
+
const bobMasterCertificate = await createMasterCertificate(walletB, bobFields)
|
|
269
|
+
const bobVerifiableCertificate = await createVerifiableCertificate(
|
|
270
|
+
bobMasterCertificate,
|
|
271
|
+
walletB,
|
|
272
|
+
alicePubKey,
|
|
273
|
+
['libraryCardNumber']
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
// Alice requires Bob to present his library card number
|
|
277
|
+
const aliceCertificatesToRequest = {
|
|
278
|
+
certifiers: [certifierPublicKey],
|
|
279
|
+
types: { [certificateType]: ['libraryCardNumber'] }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const { aliceReceivedCertificates } = setupPeers(true, false, { aliceCertsToRequest: aliceCertificatesToRequest })
|
|
283
|
+
mockGetVerifiableCertificates(undefined, bobVerifiableCertificate, alicePubKey, bobPubKey)
|
|
284
|
+
|
|
285
|
+
const aliceAcceptedLibraryCard = jest.fn()
|
|
286
|
+
|
|
287
|
+
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
288
|
+
for (const cert of certificates) {
|
|
289
|
+
// Decrypt Bob's certificate fields
|
|
290
|
+
const decryptedFields = await decryptCertificateFields(cert, walletA, walletB)
|
|
291
|
+
|
|
292
|
+
// Check and use the decrypted fields
|
|
293
|
+
if (Object.keys(decryptedFields).length !== 0 && decryptedFields.libraryCardNumber) {
|
|
294
|
+
console.log(`Alice received Bob's library card number: ${decryptedFields.libraryCardNumber}`)
|
|
295
|
+
aliceAcceptedLibraryCard()
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
301
|
+
bob.listenForGeneralMessages((senderPublicKey, payload) => {
|
|
302
|
+
console.log('Bob received message from Alice:', Utils.toUTF8(payload))
|
|
303
|
+
resolve()
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
// Alice sends a message to Bob requesting his library card before lending him a book
|
|
308
|
+
await alice.toPeer(Utils.toArray('Please present your library card to borrow a book.'))
|
|
309
|
+
await aliceReceivedCertificates
|
|
310
|
+
await bobReceivedGeneralMessage
|
|
311
|
+
|
|
312
|
+
expect(aliceAcceptedLibraryCard).toHaveBeenCalled()
|
|
313
|
+
expect(certificatesReceivedByAlice).toEqual([bobVerifiableCertificate])
|
|
314
|
+
expect(certificatesReceivedByBob).toEqual([]) // Bob did not request any certificates
|
|
315
|
+
}, 15000)
|
|
316
|
+
|
|
317
|
+
it('Bob requests additional certificates from Alice after initial communication', async () => {
|
|
318
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
319
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
320
|
+
|
|
321
|
+
const aliceMasterCertificate = await createMasterCertificate(walletA, { name: 'Alice' })
|
|
322
|
+
const aliceVerifiableCertificate = await createVerifiableCertificate(
|
|
323
|
+
aliceMasterCertificate,
|
|
324
|
+
walletA,
|
|
325
|
+
bobPubKey,
|
|
326
|
+
['name']
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
const { bobReceivedCertificates } = setupPeers(false, true)
|
|
330
|
+
mockGetVerifiableCertificates(aliceVerifiableCertificate, undefined, alicePubKey, bobPubKey)
|
|
331
|
+
|
|
332
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
333
|
+
bob.listenForGeneralMessages(async (senderPublicKey, payload) => {
|
|
334
|
+
await bobReceivedCertificates
|
|
335
|
+
console.log('Bob received message:', Utils.toUTF8(payload))
|
|
336
|
+
|
|
337
|
+
// Bob requests additional certificates after initial communication
|
|
338
|
+
await bob.requestCertificates(certificatesToRequest, senderPublicKey)
|
|
339
|
+
resolve()
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
// Initial communication from Alice
|
|
344
|
+
await alice.toPeer(Utils.toArray('Hello Bob!'))
|
|
345
|
+
await bobReceivedGeneralMessage
|
|
346
|
+
|
|
347
|
+
// Listen for certificates received from the additional request
|
|
348
|
+
const bobReceivedAdditionalCertificates = new Promise<void>((resolve) => {
|
|
349
|
+
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
350
|
+
if (certificates.length > 0) {
|
|
351
|
+
// Decrypt to confirm
|
|
352
|
+
for (const cert of certificates) {
|
|
353
|
+
const decrypted = await decryptCertificateFields(cert, walletB, walletA)
|
|
354
|
+
console.log('Bob received additional certificates from Alice:', cert)
|
|
355
|
+
console.log('Decrypted fields:', decrypted)
|
|
356
|
+
}
|
|
357
|
+
resolve()
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
await bobReceivedAdditionalCertificates
|
|
363
|
+
|
|
364
|
+
expect(certificatesReceivedByBob).toEqual([aliceVerifiableCertificate])
|
|
365
|
+
}, 15000)
|
|
366
|
+
|
|
367
|
+
it('Bob requests Alice to provide her membership status before granting access to premium content', async () => {
|
|
368
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
369
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
370
|
+
|
|
371
|
+
// Alice's certificate includes her membership status
|
|
372
|
+
const aliceMasterCertificate = await createMasterCertificate(walletA, { ...aliceFields, membershipStatus: 'Gold' })
|
|
373
|
+
const aliceVerifiableCertificate = await createVerifiableCertificate(
|
|
374
|
+
aliceMasterCertificate,
|
|
375
|
+
walletA,
|
|
376
|
+
bobPubKey,
|
|
377
|
+
['membershipStatus']
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
// Bob requires Alice to present her membership status
|
|
381
|
+
const bobCertificatesToRequest = {
|
|
382
|
+
certifiers: [certifierPublicKey],
|
|
383
|
+
types: { [certificateType]: ['membershipStatus'] }
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const { bobReceivedCertificates } = setupPeers(false, true, { bobCertsToRequest: bobCertificatesToRequest })
|
|
387
|
+
mockGetVerifiableCertificates(aliceVerifiableCertificate, undefined, alicePubKey, bobPubKey)
|
|
388
|
+
|
|
389
|
+
const bobAcceptedMembershipStatus = jest.fn()
|
|
390
|
+
|
|
391
|
+
const waitForCerts = new Promise<void>((resolve) => {
|
|
392
|
+
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
393
|
+
for (const cert of certificates) {
|
|
394
|
+
// Decrypt Alice's certificate fields
|
|
395
|
+
const decryptedFields = await decryptCertificateFields(cert, walletB, walletA)
|
|
396
|
+
if (decryptedFields.membershipStatus) {
|
|
397
|
+
console.log(`Bob received Alice's membership status: ${decryptedFields.membershipStatus}`)
|
|
398
|
+
bobAcceptedMembershipStatus()
|
|
399
|
+
resolve()
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
406
|
+
bob.listenForGeneralMessages((senderPublicKey, payload) => {
|
|
407
|
+
console.log('Bob received message from Alice:', Utils.toUTF8(payload))
|
|
408
|
+
resolve()
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
// Alice sends a message to Bob requesting access to premium content
|
|
413
|
+
await alice.toPeer(Utils.toArray('I would like to access the premium content.'))
|
|
414
|
+
await bobReceivedCertificates
|
|
415
|
+
await bobReceivedGeneralMessage
|
|
416
|
+
await waitForCerts
|
|
417
|
+
|
|
418
|
+
expect(bobAcceptedMembershipStatus).toHaveBeenCalled()
|
|
419
|
+
expect(certificatesReceivedByBob).toEqual([aliceVerifiableCertificate])
|
|
420
|
+
expect(certificatesReceivedByAlice).toEqual([]) // Alice did not request any certificates
|
|
421
|
+
}, 15000)
|
|
422
|
+
|
|
423
|
+
it('Both peers require each other\'s driver\'s license before carpooling', async () => {
|
|
424
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
425
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
426
|
+
|
|
427
|
+
// Both Alice and Bob have driver's license certificates
|
|
428
|
+
const aliceMasterCertificate = await createMasterCertificate(walletA, { ...aliceFields, driversLicenseNumber: 'DLA123456' })
|
|
429
|
+
const aliceVerifiableCertificate = await createVerifiableCertificate(
|
|
430
|
+
aliceMasterCertificate,
|
|
431
|
+
walletA,
|
|
432
|
+
bobPubKey,
|
|
433
|
+
['driversLicenseNumber']
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
const bobMasterCertificate = await createMasterCertificate(walletB, { ...bobFields, driversLicenseNumber: 'DLB654321' })
|
|
437
|
+
const bobVerifiableCertificate = await createVerifiableCertificate(
|
|
438
|
+
bobMasterCertificate,
|
|
439
|
+
walletB,
|
|
440
|
+
alicePubKey,
|
|
441
|
+
['driversLicenseNumber']
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
// Both peers require the driver's license number
|
|
445
|
+
const certificatesToRequestDriversLicense = {
|
|
446
|
+
certifiers: [certifierPublicKey],
|
|
447
|
+
types: { [certificateType]: ['driversLicenseNumber'] }
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const { aliceReceivedCertificates, bobReceivedCertificates } = setupPeers(true, true, {
|
|
451
|
+
aliceCertsToRequest: certificatesToRequestDriversLicense,
|
|
452
|
+
bobCertsToRequest: certificatesToRequestDriversLicense
|
|
453
|
+
})
|
|
454
|
+
mockGetVerifiableCertificates(aliceVerifiableCertificate, bobVerifiableCertificate, alicePubKey, bobPubKey)
|
|
455
|
+
|
|
456
|
+
const aliceAcceptedBobDL = jest.fn()
|
|
457
|
+
const bobAcceptedAliceDL = jest.fn()
|
|
458
|
+
|
|
459
|
+
const waitForAliceToAcceptBobDL = new Promise<void>((resolve) => {
|
|
460
|
+
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
461
|
+
for (const cert of certificates) {
|
|
462
|
+
const decryptedFields = await decryptCertificateFields(cert, walletA, walletB)
|
|
463
|
+
if (decryptedFields.driversLicenseNumber) {
|
|
464
|
+
console.log(`Alice received Bob's driver's license number: ${decryptedFields.driversLicenseNumber}`)
|
|
465
|
+
aliceAcceptedBobDL()
|
|
466
|
+
resolve()
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
})
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
const waitForBobToAcceptAliceDL = new Promise<void>((resolve) => {
|
|
473
|
+
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
474
|
+
for (const cert of certificates) {
|
|
475
|
+
const decryptedFields = await decryptCertificateFields(cert, walletB, walletA)
|
|
476
|
+
if (decryptedFields.driversLicenseNumber) {
|
|
477
|
+
console.log(`Bob received Alice's driver's license number: ${decryptedFields.driversLicenseNumber}`)
|
|
478
|
+
bobAcceptedAliceDL()
|
|
479
|
+
resolve()
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
})
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
486
|
+
bob.listenForGeneralMessages(async (senderPublicKey, payload) => {
|
|
487
|
+
console.log('Bob received message from Alice:', Utils.toUTF8(payload))
|
|
488
|
+
await bob.toPeer(Utils.toArray('Looking forward to carpooling!'), senderPublicKey)
|
|
489
|
+
resolve()
|
|
490
|
+
})
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
const aliceReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
494
|
+
alice.listenForGeneralMessages((senderPublicKey, payload) => {
|
|
495
|
+
console.log('Alice received message from Bob:', Utils.toUTF8(payload))
|
|
496
|
+
resolve()
|
|
497
|
+
})
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
// Alice initiates the conversation
|
|
501
|
+
await alice.toPeer(Utils.toArray('Please share your driver\'s license number for carpooling.'))
|
|
502
|
+
await aliceReceivedCertificates
|
|
503
|
+
await bobReceivedCertificates
|
|
504
|
+
await bobReceivedGeneralMessage
|
|
505
|
+
await aliceReceivedGeneralMessage
|
|
506
|
+
|
|
507
|
+
// Wait for both sides to fully accept each other's certificate
|
|
508
|
+
await waitForAliceToAcceptBobDL
|
|
509
|
+
await waitForBobToAcceptAliceDL
|
|
510
|
+
|
|
511
|
+
expect(aliceAcceptedBobDL).toHaveBeenCalled()
|
|
512
|
+
expect(bobAcceptedAliceDL).toHaveBeenCalled()
|
|
513
|
+
expect(certificatesReceivedByAlice).toEqual([bobVerifiableCertificate])
|
|
514
|
+
expect(certificatesReceivedByBob).toEqual([aliceVerifiableCertificate])
|
|
515
|
+
}, 20000)
|
|
516
|
+
|
|
517
|
+
it('Peers accept partial certificates if at least one required field is present', async () => {
|
|
518
|
+
const alicePubKey = (await walletA.getPublicKey({ identityKey: true })).publicKey
|
|
519
|
+
const bobPubKey = (await walletB.getPublicKey({ identityKey: true })).publicKey
|
|
520
|
+
|
|
521
|
+
// Alice's certificate contains 'name' and 'email'; Bob's contains only 'email'
|
|
522
|
+
const aliceMasterCertificate = await createMasterCertificate(walletA, { name: 'Alice', email: 'alice@example.com' })
|
|
523
|
+
const aliceVerifiableCertificate = await createVerifiableCertificate(
|
|
524
|
+
aliceMasterCertificate,
|
|
525
|
+
walletA,
|
|
526
|
+
bobPubKey,
|
|
527
|
+
['name', 'email']
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
const bobMasterCertificate = await createMasterCertificate(walletB, { email: 'bob@example.com' })
|
|
531
|
+
const bobVerifiableCertificate = await createVerifiableCertificate(
|
|
532
|
+
bobMasterCertificate,
|
|
533
|
+
walletB,
|
|
534
|
+
alicePubKey,
|
|
535
|
+
['email']
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
const partialCertificatesToRequest = {
|
|
539
|
+
certifiers: [certifierPublicKey],
|
|
540
|
+
types: { [certificateType]: ['name', 'email'] }
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const { aliceReceivedCertificates, bobReceivedCertificates } = setupPeers(true, true, {
|
|
544
|
+
aliceCertsToRequest: partialCertificatesToRequest,
|
|
545
|
+
bobCertsToRequest: partialCertificatesToRequest
|
|
546
|
+
})
|
|
547
|
+
mockGetVerifiableCertificates(aliceVerifiableCertificate, bobVerifiableCertificate, alicePubKey, bobPubKey)
|
|
548
|
+
|
|
549
|
+
const aliceAcceptedPartialCert = jest.fn()
|
|
550
|
+
const bobAcceptedPartialCert = jest.fn()
|
|
551
|
+
|
|
552
|
+
const waitForAlicePartialCert = new Promise<void>((resolve) => {
|
|
553
|
+
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
554
|
+
for (const cert of certificates) {
|
|
555
|
+
const decryptedFields = await decryptCertificateFields(cert, walletA, walletB)
|
|
556
|
+
if (decryptedFields.email || decryptedFields.name) {
|
|
557
|
+
console.log(`Alice received Bob's certificate with fields: ${Object.keys(decryptedFields).join(', ')}`)
|
|
558
|
+
aliceAcceptedPartialCert()
|
|
559
|
+
resolve()
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
})
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
const waitForBobPartialCert = new Promise<void>((resolve) => {
|
|
566
|
+
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
567
|
+
for (const cert of certificates) {
|
|
568
|
+
const decryptedFields = await decryptCertificateFields(cert, walletB, walletA)
|
|
569
|
+
if (decryptedFields.email || decryptedFields.name) {
|
|
570
|
+
console.log(`Bob received Alice's certificate with fields: ${Object.keys(decryptedFields).join(', ')}`)
|
|
571
|
+
bobAcceptedPartialCert()
|
|
572
|
+
resolve()
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
})
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
const bobReceivedGeneralMessage = new Promise<void>((resolve) => {
|
|
579
|
+
bob.listenForGeneralMessages((senderPublicKey, payload) => {
|
|
580
|
+
console.log('Bob received message:', Utils.toUTF8(payload))
|
|
581
|
+
resolve()
|
|
582
|
+
})
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
await alice.toPeer(Utils.toArray('Hello Bob!'))
|
|
586
|
+
await aliceReceivedCertificates
|
|
587
|
+
await bobReceivedCertificates
|
|
588
|
+
await bobReceivedGeneralMessage
|
|
589
|
+
|
|
590
|
+
// Wait for both sides to fully accept the partial cert
|
|
591
|
+
await waitForAlicePartialCert
|
|
592
|
+
await waitForBobPartialCert
|
|
593
|
+
|
|
594
|
+
expect(aliceAcceptedPartialCert).toHaveBeenCalled()
|
|
595
|
+
expect(bobAcceptedPartialCert).toHaveBeenCalled()
|
|
596
|
+
expect(certificatesReceivedByAlice).toEqual([bobVerifiableCertificate])
|
|
597
|
+
expect(certificatesReceivedByBob).toEqual([aliceVerifiableCertificate])
|
|
598
|
+
}, 20000)
|
|
599
|
+
})
|