1- import { StreamID , StreamPartID , UserID , waitForEvent } from '@streamr/utils'
1+ import { hexToBinary , StreamID , StreamPartID , StreamPartIDUtils , UserID , waitForEvent } from '@streamr/utils'
22import crypto from 'crypto'
33import { Lifecycle , inject , scoped } from 'tsyringe'
44import { Identity , IdentityInjectionToken } from '../identity/Identity'
@@ -9,12 +9,35 @@ import { uuid } from '../utils/uuid'
99import { GroupKey } from './GroupKey'
1010import { LocalGroupKeyStore } from './LocalGroupKeyStore'
1111import { SubscriberKeyExchange } from './SubscriberKeyExchange'
12+ import { StreamIDBuilder } from '../StreamIDBuilder'
13+ import { createLazyMap , Mapping } from '../utils/Mapping'
14+ import { StreamrClientError } from '../StreamrClientError'
15+
16+ /**
17+ * Gets an explicit encryption key from config for a given stream.
18+ * Returns undefined if no key is configured for the stream.
19+ */
20+ export const getExplicitKey = async (
21+ streamId : StreamID ,
22+ streamIdBuilder : StreamIDBuilder ,
23+ config : StrictStreamrClientConfig [ 'encryption' ]
24+ ) : Promise < GroupKey | undefined > => {
25+ if ( config . keys !== undefined ) {
26+ for ( const entry of Object . entries ( config . keys ) ) {
27+ if ( await streamIdBuilder . toStreamID ( entry [ 0 ] ) === streamId ) {
28+ return new GroupKey ( entry [ 1 ] . id , Buffer . from ( hexToBinary ( entry [ 1 ] . data ) ) )
29+ }
30+ }
31+ }
32+ return undefined
33+ }
1234
1335@scoped ( Lifecycle . ContainerScoped )
1436export class GroupKeyManager {
1537
1638 private readonly subscriberKeyExchange : SubscriberKeyExchange
1739 private readonly localGroupKeyStore : LocalGroupKeyStore
40+ private readonly explicitKeys ?: Mapping < StreamID , GroupKey | undefined >
1841 private readonly config : Pick < StrictStreamrClientConfig , 'encryption' >
1942 private readonly identity : Identity
2043 private readonly eventEmitter : StreamrClientEventEmitter
@@ -23,6 +46,7 @@ export class GroupKeyManager {
2346 constructor (
2447 subscriberKeyExchange : SubscriberKeyExchange ,
2548 localGroupKeyStore : LocalGroupKeyStore ,
49+ streamIdBuilder : StreamIDBuilder ,
2650 @inject ( ConfigInjectionToken ) config : Pick < StrictStreamrClientConfig , 'encryption' > ,
2751 @inject ( IdentityInjectionToken ) identity : Identity ,
2852 eventEmitter : StreamrClientEventEmitter ,
@@ -34,16 +58,35 @@ export class GroupKeyManager {
3458 this . identity = identity
3559 this . eventEmitter = eventEmitter
3660 this . destroySignal = destroySignal
61+ if ( config . encryption . keys !== undefined ) {
62+ this . explicitKeys = createLazyMap ( {
63+ valueFactory : async ( streamId : StreamID ) => {
64+ return getExplicitKey ( streamId , streamIdBuilder , config . encryption )
65+ }
66+ } )
67+ }
3768 }
3869
3970 async fetchKey ( streamPartId : StreamPartID , groupKeyId : string , publisherId : UserID ) : Promise < GroupKey > {
40- // 1st try: local storage
71+ // If explicit keys are defined only those keys are used.
72+ if ( this . explicitKeys !== undefined ) {
73+ const explicitKey = await this . explicitKeys . get ( StreamPartIDUtils . getStreamID ( streamPartId ) )
74+ if ( explicitKey !== undefined ) {
75+ return explicitKey
76+ }
77+ throw new StreamrClientError (
78+ `No encryption key available for stream part ID: groupKeyId=${ groupKeyId } , streamPartId=${ streamPartId } ` ,
79+ 'UNEXPECTED_INPUT'
80+ )
81+ }
82+
83+ // 2nd try: local storage
4184 let groupKey = await this . localGroupKeyStore . get ( groupKeyId , publisherId )
4285 if ( groupKey !== undefined ) {
4386 return groupKey
4487 }
4588
46- // 2nd try: Streamr key-exchange
89+ // 3rd try: Streamr key-exchange
4790 await this . subscriberKeyExchange . requestGroupKey ( groupKeyId , publisherId , streamPartId )
4891 const groupKeyIds = await waitForEvent (
4992 // TODO remove "as any" type casing in NET-889
0 commit comments