@@ -15,7 +15,8 @@ import { sha256 } from './crypto/encryption'
15
15
// Message header carries the sender and recipient keys used to protect message.
16
16
// Message timestamp is set by the sender.
17
17
export default class Message implements proto . Message {
18
- header : proto . Message_Header | undefined // eslint-disable-line camelcase
18
+ header : proto . MessageHeader | undefined // eslint-disable-line camelcase
19
+ headerBytes : Uint8Array // encoded header bytes
19
20
ciphertext : Ciphertext | undefined
20
21
decrypted : string | undefined
21
22
error ?: Error
@@ -27,10 +28,16 @@ export default class Message implements proto.Message {
27
28
id : string
28
29
private bytes : Uint8Array
29
30
30
- constructor ( id : string , bytes : Uint8Array , obj : proto . Message ) {
31
+ constructor (
32
+ id : string ,
33
+ bytes : Uint8Array ,
34
+ obj : proto . Message ,
35
+ header : proto . MessageHeader
36
+ ) {
31
37
this . id = id
32
38
this . bytes = bytes
33
- this . header = obj . header
39
+ this . headerBytes = obj . headerBytes
40
+ this . header = header
34
41
if ( obj . ciphertext ) {
35
42
this . ciphertext = new Ciphertext ( obj . ciphertext )
36
43
}
@@ -40,14 +47,19 @@ export default class Message implements proto.Message {
40
47
return this . bytes
41
48
}
42
49
43
- static async create ( obj : proto . Message ) : Promise < Message > {
44
- const bytes = proto . Message . encode ( obj ) . finish ( )
50
+ static async create (
51
+ obj : proto . Message ,
52
+ header : proto . MessageHeader ,
53
+ bytes : Uint8Array
54
+ ) : Promise < Message > {
45
55
const id = bytesToHex ( await sha256 ( bytes ) )
46
- return new Message ( id , bytes , obj )
56
+ return new Message ( id , bytes , obj , header )
47
57
}
48
58
49
59
static async fromBytes ( bytes : Uint8Array ) : Promise < Message > {
50
- return Message . create ( proto . Message . decode ( bytes ) )
60
+ const msg = proto . Message . decode ( bytes )
61
+ const header = proto . MessageHeader . decode ( msg . headerBytes )
62
+ return Message . create ( msg , header , bytes )
51
63
}
52
64
53
65
get text ( ) : string | undefined {
@@ -85,26 +97,24 @@ export default class Message implements proto.Message {
85
97
message : string ,
86
98
timestamp : Date
87
99
) : Promise < Message > {
88
- const bytes = new TextEncoder ( ) . encode ( message )
100
+ const msgBytes = new TextEncoder ( ) . encode ( message )
89
101
90
102
const secret = await sender . sharedSecret (
91
103
recipient ,
92
104
sender . getCurrentPreKey ( ) . publicKey ,
93
105
false
94
106
)
95
107
// eslint-disable-next-line camelcase
96
- const header : proto . Message_Header = {
108
+ const header : proto . MessageHeader = {
97
109
sender : sender . getPublicKeyBundle ( ) ,
98
110
recipient,
99
111
timestamp : timestamp . getTime ( ) ,
100
112
}
101
- const headerBytes = proto . Message_Header . encode ( header ) . finish ( )
102
- const ciphertext = await encrypt ( bytes , secret , headerBytes )
103
-
104
- const msg = await Message . create ( {
105
- header,
106
- ciphertext,
107
- } )
113
+ const headerBytes = proto . MessageHeader . encode ( header ) . finish ( )
114
+ const ciphertext = await encrypt ( msgBytes , secret , headerBytes )
115
+ const protoMsg = { headerBytes : headerBytes , ciphertext }
116
+ const bytes = proto . Message . encode ( protoMsg ) . finish ( )
117
+ const msg = await Message . create ( protoMsg , header , bytes )
108
118
msg . decrypted = message
109
119
return msg
110
120
}
@@ -117,45 +127,41 @@ export default class Message implements proto.Message {
117
127
bytes : Uint8Array
118
128
) : Promise < Message > {
119
129
const message = proto . Message . decode ( bytes )
120
- if ( ! message . header ) {
130
+ const header = proto . MessageHeader . decode ( message . headerBytes )
131
+ if ( ! header ) {
121
132
throw new Error ( 'missing message header' )
122
133
}
123
- if ( ! message . header . sender ) {
134
+ if ( ! header . sender ) {
124
135
throw new Error ( 'missing message sender' )
125
136
}
126
- if ( ! message . header . sender . identityKey ) {
137
+ if ( ! header . sender . identityKey ) {
127
138
throw new Error ( 'missing message sender identity key' )
128
139
}
129
- if ( ! message . header . sender . preKey ) {
140
+ if ( ! header . sender . preKey ) {
130
141
throw new Error ( 'missing message sender pre-key' )
131
142
}
132
- if ( ! message . header . recipient ) {
143
+ if ( ! header . recipient ) {
133
144
throw new Error ( 'missing message recipient' )
134
145
}
135
- if ( ! message . header . recipient . identityKey ) {
146
+ if ( ! header . recipient . identityKey ) {
136
147
throw new Error ( 'missing message recipient identity-key' )
137
148
}
138
- if ( ! message . header . recipient . preKey ) {
149
+ if ( ! header . recipient . preKey ) {
139
150
throw new Error ( 'missing message recipient pre-key' )
140
151
}
141
152
const recipient = new PublicKeyBundle (
142
- new PublicKey ( message . header . recipient . identityKey ) ,
143
- new PublicKey ( message . header . recipient . preKey )
153
+ new PublicKey ( header . recipient . identityKey ) ,
154
+ new PublicKey ( header . recipient . preKey )
144
155
)
145
156
const sender = new PublicKeyBundle (
146
- new PublicKey ( message . header . sender . identityKey ) ,
147
- new PublicKey ( message . header . sender . preKey )
157
+ new PublicKey ( header . sender . identityKey ) ,
158
+ new PublicKey ( header . sender . preKey )
148
159
)
149
- const headerBytes = proto . Message_Header . encode ( {
150
- sender : sender ,
151
- recipient : recipient ,
152
- timestamp : message . header . timestamp ,
153
- } ) . finish ( )
154
160
if ( ! message . ciphertext ?. aes256GcmHkdfSha256 ) {
155
161
throw new Error ( 'missing message ciphertext' )
156
162
}
157
163
const ciphertext = new Ciphertext ( message . ciphertext )
158
- const msg = await Message . create ( message )
164
+ const msg = await Message . create ( message , header , bytes )
159
165
let secret : Uint8Array
160
166
try {
161
167
if ( viewer . identityKey . matches ( sender . identityKey ) ) {
@@ -172,7 +178,7 @@ export default class Message implements proto.Message {
172
178
msg . error = e
173
179
return msg
174
180
}
175
- bytes = await decrypt ( ciphertext , secret , headerBytes )
181
+ bytes = await decrypt ( ciphertext , secret , message . headerBytes )
176
182
msg . decrypted = new TextDecoder ( ) . decode ( bytes )
177
183
return msg
178
184
}
0 commit comments