1- function SessionCipher ( storage , remoteAddress ) {
1+ function SessionCipher ( storage , remoteAddress , options ) {
2+ options = options || { } ;
3+
4+ if ( typeof options . messageKeysLimit === 'undefined' ) {
5+ options . messageKeysLimit = 1000 ;
6+ }
7+
8+ this . messageKeysLimit = options . messageKeysLimit ;
29 this . remoteAddress = remoteAddress ;
310 this . storage = storage ;
411}
@@ -76,10 +83,20 @@ SessionCipher.prototype = {
7683 result . set ( new Uint8Array ( encodedMsg ) , 1 ) ;
7784 result . set ( new Uint8Array ( mac , 0 , 8 ) , encodedMsg . byteLength + 1 ) ;
7885
79- record . updateSessionState ( session ) ;
80- return this . storage . storeSession ( address , record . serialize ( ) ) . then ( function ( ) {
81- return result ;
82- } ) ;
86+ return this . storage . isTrustedIdentity (
87+ this . remoteAddress . getName ( ) , util . toArrayBuffer ( session . indexInfo . remoteIdentityKey ) , this . storage . Direction . SENDING
88+ ) . then ( function ( trusted ) {
89+ if ( ! trusted ) {
90+ throw new Error ( 'Identity key changed' ) ;
91+ }
92+ } ) . then ( function ( ) {
93+ return this . storage . saveIdentity ( this . remoteAddress . toString ( ) , session . indexInfo . remoteIdentityKey ) ;
94+ } . bind ( this ) ) . then ( function ( ) {
95+ record . updateSessionState ( session ) ;
96+ return this . storage . storeSession ( address , record . serialize ( ) ) . then ( function ( ) {
97+ return result ;
98+ } ) ;
99+ } . bind ( this ) ) ;
83100 } . bind ( this ) ) ;
84101 } . bind ( this ) ) ;
85102 } . bind ( this ) ) . then ( function ( message ) {
@@ -89,22 +106,24 @@ SessionCipher.prototype = {
89106 preKeyMsg . registrationId = myRegistrationId ;
90107
91108 preKeyMsg . baseKey = util . toArrayBuffer ( session . pendingPreKey . baseKey ) ;
92- preKeyMsg . preKeyId = session . pendingPreKey . preKeyId ;
109+ if ( session . pendingPreKey . preKeyId ) {
110+ preKeyMsg . preKeyId = session . pendingPreKey . preKeyId ;
111+ }
93112 preKeyMsg . signedPreKeyId = session . pendingPreKey . signedKeyId ;
94113
95114 preKeyMsg . message = message ;
96115 var result = String . fromCharCode ( ( 3 << 4 ) | 3 ) + util . toString ( preKeyMsg . encode ( ) ) ;
97116 return {
98117 type : 3 ,
99118 body : result ,
100- registrationId : record . registrationId
119+ registrationId : session . registrationId
101120 } ;
102121
103122 } else {
104123 return {
105124 type : 1 ,
106125 body : util . toString ( message ) ,
107- registrationId : record . registrationId
126+ registrationId : session . registrationId
108127 } ;
109128 }
110129 } ) ;
@@ -122,6 +141,10 @@ SessionCipher.prototype = {
122141 return this . doDecryptWhisperMessage ( buffer , session ) . then ( function ( plaintext ) {
123142 return { plaintext : plaintext , session : session } ;
124143 } ) . catch ( function ( e ) {
144+ if ( e . name === 'MessageCounterError' ) {
145+ return Promise . reject ( e ) ;
146+ }
147+
125148 errors . push ( e ) ;
126149 return this . decryptWithSessionList ( buffer , sessionList , errors ) ;
127150 } . bind ( this ) ) ;
@@ -137,10 +160,25 @@ SessionCipher.prototype = {
137160 var errors = [ ] ;
138161 return this . decryptWithSessionList ( buffer , record . getSessions ( ) , errors ) . then ( function ( result ) {
139162 return this . getRecord ( address ) . then ( function ( record ) {
140- record . updateSessionState ( result . session ) ;
141- return this . storage . storeSession ( address , record . serialize ( ) ) . then ( function ( ) {
142- return result . plaintext ;
143- } ) ;
163+ if ( result . session . indexInfo . baseKey !== record . getOpenSession ( ) . indexInfo . baseKey ) {
164+ record . archiveCurrentState ( ) ;
165+ record . promoteState ( result . session ) ;
166+ }
167+
168+ return this . storage . isTrustedIdentity (
169+ this . remoteAddress . getName ( ) , util . toArrayBuffer ( result . session . indexInfo . remoteIdentityKey ) , this . storage . Direction . RECEIVING
170+ ) . then ( function ( trusted ) {
171+ if ( ! trusted ) {
172+ throw new Error ( 'Identity key changed' ) ;
173+ }
174+ } ) . then ( function ( ) {
175+ return this . storage . saveIdentity ( this . remoteAddress . toString ( ) , result . session . indexInfo . remoteIdentityKey ) ;
176+ } . bind ( this ) ) . then ( function ( ) {
177+ record . updateSessionState ( result . session ) ;
178+ return this . storage . storeSession ( address , record . serialize ( ) ) . then ( function ( ) {
179+ return result . plaintext ;
180+ } ) ;
181+ } . bind ( this ) ) ;
144182 } . bind ( this ) ) ;
145183 } . bind ( this ) ) ;
146184 } . bind ( this ) ) ;
@@ -161,19 +199,19 @@ SessionCipher.prototype = {
161199 throw new Error ( "No registrationId" ) ;
162200 }
163201 record = new Internal . SessionRecord (
164- util . toString ( preKeyProto . identityKey ) ,
165202 preKeyProto . registrationId
166203 ) ;
167204 }
168205 var builder = new SessionBuilder ( this . storage , this . remoteAddress ) ;
206+ // isTrustedIdentity is called within processV3, no need to call it here
169207 return builder . processV3 ( record , preKeyProto ) . then ( function ( preKeyId ) {
170208 var session = record . getSessionByBaseKey ( preKeyProto . baseKey ) ;
171209 return this . doDecryptWhisperMessage (
172210 preKeyProto . message . toArrayBuffer ( ) , session
173211 ) . then ( function ( plaintext ) {
174212 record . updateSessionState ( session ) ;
175213 return this . storage . storeSession ( address , record . serialize ( ) ) . then ( function ( ) {
176- if ( preKeyId !== undefined ) {
214+ if ( preKeyId !== undefined && preKeyId !== null ) {
177215 return this . storage . removePreKey ( preKeyId ) ;
178216 }
179217 } . bind ( this ) ) . then ( function ( ) {
@@ -240,7 +278,7 @@ SessionCipher.prototype = {
240278 } ) ;
241279 } ,
242280 fillMessageKeys : function ( chain , counter ) {
243- if ( Object . keys ( chain . messageKeys ) . length >= 1000 ) {
281+ if ( this . messageKeysLimit && Object . keys ( chain . messageKeys ) . length >= this . messageKeysLimit ) {
244282 console . log ( "Too many message keys for chain" ) ;
245283 return Promise . resolve ( ) ; // Stalker, much?
246284 }
@@ -330,7 +368,11 @@ SessionCipher.prototype = {
330368 if ( record === undefined ) {
331369 return undefined ;
332370 }
333- return record . registrationId ;
371+ var openSession = record . getOpenSession ( ) ;
372+ if ( openSession === undefined ) {
373+ return null ;
374+ }
375+ return openSession . registrationId ;
334376 } ) ;
335377 } . bind ( this ) ) ;
336378 } ,
@@ -359,8 +401,8 @@ SessionCipher.prototype = {
359401 }
360402} ;
361403
362- libsignal . SessionCipher = function ( storage , remoteAddress ) {
363- var cipher = new SessionCipher ( storage , remoteAddress ) ;
404+ libsignal . SessionCipher = function ( storage , remoteAddress , options ) {
405+ var cipher = new SessionCipher ( storage , remoteAddress , options ) ;
364406
365407 // returns a Promise that resolves to a ciphertext object
366408 this . encrypt = cipher . encrypt . bind ( cipher ) ;
0 commit comments