@@ -70,24 +70,27 @@ type GroupKeyStoreOptions = {
7070 groupKeys : [ GroupKeyId , GroupKey ] [ ]
7171}
7272
73- function GroupKeyStore ( { clientId, streamId, groupKeys } : GroupKeyStoreOptions ) {
74- const store = new PersistentStore ( { clientId, streamId } )
75-
76- let currentGroupKeyId : GroupKeyId | undefined // current key id if any
77- const nextGroupKeys : GroupKey [ ] = [ ] // the keys to use next, disappears if not actually used. Max queue size 2
78-
79- groupKeys . forEach ( ( [ groupKeyId , groupKey ] ) => {
80- GroupKey . validate ( groupKey )
81- if ( groupKeyId !== groupKey . id ) {
82- throw new Error ( `Ids must match: groupKey.id: ${ groupKey . id } , groupKeyId: ${ groupKeyId } ` )
83- }
84- // use last init key as current
85- currentGroupKeyId = groupKey . id
86- } )
73+ export class GroupKeyStore {
74+ store
75+ currentGroupKeyId : GroupKeyId | undefined // current key id if any
76+ nextGroupKeys : GroupKey [ ] = [ ] // the keys to use next, disappears if not actually used. Max queue size 2
77+
78+ constructor ( { clientId, streamId, groupKeys } : GroupKeyStoreOptions ) {
79+ this . store = new PersistentStore ( { clientId, streamId } )
80+
81+ groupKeys . forEach ( ( [ groupKeyId , groupKey ] ) => {
82+ GroupKey . validate ( groupKey )
83+ if ( groupKeyId !== groupKey . id ) {
84+ throw new Error ( `Ids must match: groupKey.id: ${ groupKey . id } , groupKeyId: ${ groupKeyId } ` )
85+ }
86+ // use last init key as current
87+ this . currentGroupKeyId = groupKey . id
88+ } )
89+ }
8790
88- async function storeKey ( groupKey : GroupKey ) {
91+ private async storeKey ( groupKey : GroupKey ) {
8992 GroupKey . validate ( groupKey )
90- const existingKey = await store . get ( groupKey . id )
93+ const existingKey = await this . store . get ( groupKey . id )
9194 if ( existingKey ) {
9295 if ( ! existingKey . equals ( groupKey ) ) {
9396 throw new GroupKey . InvalidGroupKeyError (
@@ -96,90 +99,95 @@ function GroupKeyStore({ clientId, streamId, groupKeys }: GroupKeyStoreOptions)
9699 )
97100 }
98101
99- await store . set ( groupKey . id , existingKey )
102+ await this . store . set ( groupKey . id , existingKey )
100103 return existingKey
101104 }
102105
103- await store . set ( groupKey . id , groupKey )
106+ await this . store . set ( groupKey . id , groupKey )
104107 return groupKey
105108 }
106109
107- return {
108- async has ( id : GroupKeyId ) {
109- if ( currentGroupKeyId === id ) { return true }
110+ async has ( id : GroupKeyId ) {
111+ if ( this . currentGroupKeyId === id ) { return true }
110112
111- if ( nextGroupKeys . some ( ( nextKey ) => nextKey . id === id ) ) { return true }
113+ if ( this . nextGroupKeys . some ( ( nextKey ) => nextKey . id === id ) ) { return true }
112114
113- return store . has ( id )
114- } ,
115- async isEmpty ( ) {
116- return ! nextGroupKeys . length && await store . size ( ) === 0
117- } ,
118- async useGroupKey ( ) : Promise < [ GroupKey | undefined , GroupKey | undefined ] > {
119- const nextGroupKey = nextGroupKeys . pop ( )
120- // First use of group key on this stream, no current key. Make next key current.
121- if ( ! currentGroupKeyId && nextGroupKey ) {
122- await storeKey ( nextGroupKey )
123- currentGroupKeyId = nextGroupKey . id
124- return [
125- await this . get ( currentGroupKeyId ) ,
126- undefined ,
127- ]
128- }
115+ return this . store . has ( id )
116+ }
129117
130- // Keep using current key (empty next)
131- if ( currentGroupKeyId != null && ! nextGroupKey ) {
132- return [
133- await this . get ( currentGroupKeyId ) ,
134- undefined
135- ]
136- }
118+ async isEmpty ( ) {
119+ return ! this . nextGroupKeys . length && await this . store . size ( ) === 0
120+ }
137121
138- // Key changed (non-empty next). return current + next. Make next key current.
139- if ( currentGroupKeyId != null && nextGroupKey != null ) {
140- await storeKey ( nextGroupKey )
141- const prevGroupKey = await this . get ( currentGroupKeyId )
142- currentGroupKeyId = nextGroupKey . id
143- // use current key one more time
144- return [
145- prevGroupKey ,
146- nextGroupKey ,
147- ]
148- }
122+ async useGroupKey ( ) : Promise < [ GroupKey | undefined , GroupKey | undefined ] > {
123+ const nextGroupKey = this . nextGroupKeys . pop ( )
124+ // First use of group key on this stream, no current key. Make next key current.
125+ if ( ! this . currentGroupKeyId && nextGroupKey ) {
126+ this . currentGroupKeyId = nextGroupKey . id
127+ return [
128+ await this . get ( this . currentGroupKeyId ) ,
129+ undefined ,
130+ ]
131+ }
149132
150- // Generate & use new key if none already set.
151- await this . rotateGroupKey ( )
152- return this . useGroupKey ( )
153- } ,
154- async get ( id : GroupKeyId ) {
155- return store . get ( id )
156- } ,
157- async clear ( ) {
158- currentGroupKeyId = undefined
159- nextGroupKeys . length = 0
160- return store . clear ( )
161- } ,
162- async rotateGroupKey ( ) {
163- return this . setNextGroupKey ( GroupKey . generate ( ) )
164- } ,
165- async add ( groupKey : GroupKey ) {
166- return storeKey ( groupKey )
167- } ,
168- async setNextGroupKey ( newKey : GroupKey ) {
169- GroupKey . validate ( newKey )
170- nextGroupKeys . unshift ( newKey )
171- nextGroupKeys . length = Math . min ( nextGroupKeys . length , 2 )
172- } ,
173- async rekey ( ) {
174- const newKey = GroupKey . generate ( )
175- await storeKey ( newKey )
176- currentGroupKeyId = newKey . id
177- nextGroupKeys . length = 0
133+ // Keep using current key (empty next)
134+ if ( this . currentGroupKeyId != null && ! nextGroupKey ) {
135+ return [
136+ await this . get ( this . currentGroupKeyId ) ,
137+ undefined
138+ ]
139+ }
140+
141+ // Key changed (non-empty next). return current + next. Make next key current.
142+ if ( this . currentGroupKeyId != null && nextGroupKey != null ) {
143+ const prevId = this . currentGroupKeyId
144+ this . currentGroupKeyId = nextGroupKey . id
145+ const prevGroupKey = await this . get ( prevId )
146+ // use current key one more time
147+ return [
148+ prevGroupKey ,
149+ nextGroupKey ,
150+ ]
178151 }
152+
153+ // Generate & use new key if none already set.
154+ await this . rotateGroupKey ( )
155+ return this . useGroupKey ( )
156+ }
157+
158+ async get ( id : GroupKeyId ) {
159+ return this . store . get ( id )
160+ }
161+
162+ async clear ( ) {
163+ this . currentGroupKeyId = undefined
164+ this . nextGroupKeys . length = 0
165+ return this . store . clear ( )
166+ }
167+
168+ async rotateGroupKey ( ) {
169+ return this . setNextGroupKey ( GroupKey . generate ( ) )
170+ }
171+
172+ async add ( groupKey : GroupKey ) {
173+ return this . storeKey ( groupKey )
174+ }
175+
176+ async setNextGroupKey ( newKey : GroupKey ) {
177+ GroupKey . validate ( newKey )
178+ this . nextGroupKeys . unshift ( newKey )
179+ this . nextGroupKeys . length = Math . min ( this . nextGroupKeys . length , 2 )
180+ await this . storeKey ( newKey )
181+ }
182+
183+ async rekey ( ) {
184+ const newKey = GroupKey . generate ( )
185+ await this . storeKey ( newKey )
186+ this . currentGroupKeyId = newKey . id
187+ this . nextGroupKeys . length = 0
179188 }
180189}
181190
182- type GroupKeyStorage = ReturnType < typeof GroupKeyStore >
183191type GroupKeysSerialized = Record < GroupKeyId , GroupKeyish >
184192
185193function parseGroupKeys ( groupKeys : GroupKeysSerialized = { } ) : Map < GroupKeyId , GroupKey > {
@@ -243,7 +251,7 @@ async function catchKeyExchangeError(client: StreamrClient, streamMessage: Strea
243251 }
244252}
245253
246- async function PublisherKeyExhangeSubscription ( client : StreamrClient , getGroupKeyStore : ( streamId : string ) => Promise < GroupKeyStorage > ) {
254+ async function PublisherKeyExhangeSubscription ( client : StreamrClient , getGroupKeyStore : ( streamId : string ) => Promise < GroupKeyStore > ) {
247255 async function onKeyExchangeMessage ( _parsedContent : any , streamMessage : StreamMessage ) {
248256 return catchKeyExchangeError ( client , streamMessage , async ( ) => {
249257 if ( streamMessage . messageType !== StreamMessage . MESSAGE_TYPES . GROUP_KEY_REQUEST ) {
@@ -316,7 +324,7 @@ export function PublisherKeyExhange(client: StreamrClient, { groupKeys = {} }: K
316324 let enabled = true
317325 const getGroupKeyStore = pMemoize ( async ( streamId ) => {
318326 const clientId = await client . getAddress ( )
319- return GroupKeyStore ( {
327+ return new GroupKeyStore ( {
320328 clientId,
321329 streamId,
322330 groupKeys : [ ...parseGroupKeys ( groupKeys [ streamId ] ) . entries ( ) ]
@@ -403,7 +411,7 @@ async function getGroupKeysFromStreamMessage(streamMessage: StreamMessage, encry
403411
404412async function SubscriberKeyExhangeSubscription (
405413 client : StreamrClient ,
406- getGroupKeyStore : ( streamId : string ) => Promise < GroupKeyStorage > ,
414+ getGroupKeyStore : ( streamId : string ) => Promise < GroupKeyStore > ,
407415 encryptionUtil : EncryptionUtil
408416) {
409417 let sub : Subscription
@@ -436,7 +444,7 @@ export function SubscriberKeyExchange(client: StreamrClient, { groupKeys = {} }:
436444
437445 const getGroupKeyStore = pMemoize ( async ( streamId ) => {
438446 const clientId = await client . getAddress ( )
439- return GroupKeyStore ( {
447+ return new GroupKeyStore ( {
440448 clientId,
441449 streamId,
442450 groupKeys : [ ...parseGroupKeys ( groupKeys [ streamId ] ) . entries ( ) ]
0 commit comments