/
CommunicationClient.ts
112 lines (101 loc) · 3.18 KB
/
CommunicationClient.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
import * as sodium from 'libsodium-wrappers'
import { P2PPairingRequest } from '../..'
import { ExtendedP2PPairingResponse } from '../../types/P2PPairingResponse'
import { PostMessagePairingRequest } from '../../types/PostMessagePairingRequest'
import { ExtendedPostMessagePairingResponse } from '../../types/PostMessagePairingResponse'
import { toHex, getHexHash, sealCryptobox } from '../../utils/crypto'
/**
* @internalapi
*
*
*/
export abstract class CommunicationClient {
constructor(protected readonly keyPair: sodium.KeyPair) {}
/**
* Get the public key
*/
public async getPublicKey(): Promise<string> {
return toHex(this.keyPair.publicKey)
}
/**
* get the public key hash
*/
public async getPublicKeyHash(): Promise<string> {
return getHexHash(this.keyPair.publicKey)
}
/**
* Create a cryptobox shared key
*
* @param otherPublicKey
* @param selfPrivateKey
*/
protected async createCryptoBox(
otherPublicKey: string,
selfPrivateKey: Uint8Array
): Promise<[Uint8Array, Uint8Array, Uint8Array]> {
// TODO: Don't calculate it every time?
const kxSelfPrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(
Buffer.from(selfPrivateKey)
) // Secret bytes to scalar bytes
const kxSelfPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(
Buffer.from(selfPrivateKey).slice(32, 64)
) // Secret bytes to scalar bytes
const kxOtherPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(
Buffer.from(otherPublicKey, 'hex')
) // Secret bytes to scalar bytes
return [
Buffer.from(kxSelfPublicKey),
Buffer.from(kxSelfPrivateKey),
Buffer.from(kxOtherPublicKey)
]
}
/**
* Create a cryptobox server
*
* @param otherPublicKey
* @param selfPrivateKey
*/
protected async createCryptoBoxServer(
otherPublicKey: string,
selfPrivateKey: Uint8Array
): Promise<sodium.CryptoKX> {
const keys = await this.createCryptoBox(otherPublicKey, selfPrivateKey)
return sodium.crypto_kx_server_session_keys(...keys)
}
/**
* Create a cryptobox client
*
* @param otherPublicKey
* @param selfPrivateKey
*/
protected async createCryptoBoxClient(
otherPublicKey: string,
selfPrivateKey: Uint8Array
): Promise<sodium.CryptoKX> {
const keys = await this.createCryptoBox(otherPublicKey, selfPrivateKey)
return sodium.crypto_kx_client_session_keys(...keys)
}
/**
* Encrypt a message for a specific publicKey (receiver, asymmetric)
*
* @param recipientPublicKey
* @param message
*/
protected async encryptMessageAsymmetric(
recipientPublicKey: string,
message: string
): Promise<string> {
return sealCryptobox(message, Buffer.from(recipientPublicKey, 'hex'))
}
abstract async unsubscribeFromEncryptedMessages(): Promise<void>
abstract async unsubscribeFromEncryptedMessage(senderPublicKey: string): Promise<void>
// abstract async send(message: string, recipient?: string): Promise<void>
public abstract async sendMessage(
message: string,
peer?:
| P2PPairingRequest
| ExtendedP2PPairingResponse
| PostMessagePairingRequest
| ExtendedPostMessagePairingResponse
): Promise<void>
}