-
Notifications
You must be signed in to change notification settings - Fork 62
/
MessageBasedClient.ts
124 lines (109 loc) · 3.26 KB
/
MessageBasedClient.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { BEACON_VERSION } from '../../constants'
import {
decryptCryptoboxPayload,
encryptCryptoboxPayload,
generateGUID,
secretbox_NONCEBYTES,
secretbox_MACBYTES
} from '@airgap/beacon-utils'
import { CommunicationClient } from './CommunicationClient'
import { PostMessagePairingRequest, PostMessagePairingResponse } from '@airgap/beacon-types'
import { KeyPair } from '@stablelib/ed25519'
/**
* @internalapi
*
*
*/
export abstract class MessageBasedClient extends CommunicationClient {
/**
* The listeners that will be notified of new messages
*/
protected abstract readonly activeListeners: Map<string, unknown>
constructor(
protected readonly name: string,
keyPair: KeyPair
) {
super(keyPair)
this.init().catch(console.error)
}
/**
* start the client and make sure all dependencies are ready
*/
public async start(): Promise<void> {
await Promise.resolve()
}
/**
* Get the pairing request information. This will be shared with the peer during the connection setup
*/
public async getPairingRequestInfo(): Promise<PostMessagePairingRequest> {
return new PostMessagePairingRequest(
await generateGUID(),
this.name,
await this.getPublicKey(),
BEACON_VERSION
)
}
/**
* Get the pairing response information. This will be shared with the peer during the connection setup
*/
public async getPairingResponseInfo(
request: PostMessagePairingRequest
): Promise<PostMessagePairingResponse> {
return new PostMessagePairingResponse(
request.id,
this.name,
await this.getPublicKey(),
request.version
)
}
/**
* Unsubscribe from encrypted messages from a specific peer
*
* @param senderPublicKey
*/
public async unsubscribeFromEncryptedMessage(senderPublicKey: string): Promise<void> {
const listener = this.activeListeners.get(senderPublicKey)
if (!listener) {
return
}
this.activeListeners.delete(senderPublicKey)
}
/**
* Unsubscribe from all encrypted messages
*/
public async unsubscribeFromEncryptedMessages(): Promise<void> {
this.activeListeners.clear()
}
/**
* Decrypt a message from a specific peer
*
* @param senderPublicKey
* @param payload
*/
protected async decryptMessage(senderPublicKey: string, payload: string): Promise<string> {
const sharedKey = await this.createCryptoBoxServer(senderPublicKey, this.keyPair!)
const hexPayload = Buffer.from(payload, 'hex')
if (hexPayload.length >= secretbox_NONCEBYTES + secretbox_MACBYTES) {
try {
return await decryptCryptoboxPayload(hexPayload, sharedKey.receive)
} catch (decryptionError) {
/* NO-OP. We try to decode every message, but some might not be addressed to us. */
}
}
throw new Error('Could not decrypt message')
}
/**
* Encrypt a message for a specific publicKey (receiver)
*
* @param recipientPublicKey
* @param message
*/
protected async encryptMessage(recipientPublicKey: string, message: string): Promise<string> {
const sharedKey = await this.createCryptoBoxClient(recipientPublicKey, this.keyPair!)
return encryptCryptoboxPayload(message, sharedKey.send)
}
/**
* Initialize the connection
*/
public abstract init(): Promise<void>
}