@ -3,14 +3,16 @@ import { BehaviorSubject, concatMap } from "rxjs";
import { LogService } from "../abstractions/log.service" ;
import { LogService } from "../abstractions/log.service" ;
import { StateService as StateServiceAbstraction } from "../abstractions/state.service" ;
import { StateService as StateServiceAbstraction } from "../abstractions/state.service" ;
import { StateMigrationService } from "../abstractions/stateMigration.service" ;
import { StateMigrationService } from "../abstractions/stateMigration.service" ;
import { AbstractStorageService } from "../abstractions/storage.service" ;
import {
MemoryStorageServiceInterface ,
AbstractStorageService ,
} from "../abstractions/storage.service" ;
import { HtmlStorageLocation } from "../enums/htmlStorageLocation" ;
import { HtmlStorageLocation } from "../enums/htmlStorageLocation" ;
import { KdfType } from "../enums/kdfType" ;
import { KdfType } from "../enums/kdfType" ;
import { StorageLocation } from "../enums/storageLocation" ;
import { StorageLocation } from "../enums/storageLocation" ;
import { ThemeType } from "../enums/themeType" ;
import { ThemeType } from "../enums/themeType" ;
import { UriMatchType } from "../enums/uriMatchType" ;
import { UriMatchType } from "../enums/uriMatchType" ;
import { StateFactory } from "../factories/stateFactory" ;
import { StateFactory } from "../factories/stateFactory" ;
import { Utils } from "../misc/utils" ;
import { CipherData } from "../models/data/cipherData" ;
import { CipherData } from "../models/data/cipherData" ;
import { CollectionData } from "../models/data/collectionData" ;
import { CollectionData } from "../models/data/collectionData" ;
import { EncryptedOrganizationKeyData } from "../models/data/encryptedOrganizationKeyData" ;
import { EncryptedOrganizationKeyData } from "../models/data/encryptedOrganizationKeyData" ;
@ -76,7 +78,7 @@ export class StateService<
constructor (
constructor (
protected storageService : AbstractStorageService ,
protected storageService : AbstractStorageService ,
protected secureStorageService : AbstractStorageService ,
protected secureStorageService : AbstractStorageService ,
protected memoryStorageService : AbstractStorageService ,
protected memoryStorageService : AbstractStorageService & MemoryStorageServiceInterface ,
protected logService : LogService ,
protected logService : LogService ,
protected stateMigrationService : StateMigrationService ,
protected stateMigrationService : StateMigrationService ,
protected stateFactory : StateFactory < TGlobalState , TAccount > ,
protected stateFactory : StateFactory < TGlobalState , TAccount > ,
@ -150,6 +152,9 @@ export class StateService<
return ;
return ;
}
}
await this . updateState ( async ( state ) = > {
await this . updateState ( async ( state ) = > {
if ( state . accounts == null ) {
state . accounts = { } ;
}
state . accounts [ userId ] = this . createAccount ( ) ;
state . accounts [ userId ] = this . createAccount ( ) ;
const diskAccount = await this . getAccountFromDisk ( { userId : userId } ) ;
const diskAccount = await this . getAccountFromDisk ( { userId : userId } ) ;
state . accounts [ userId ] . profile = diskAccount . profile ;
state . accounts [ userId ] . profile = diskAccount . profile ;
@ -494,11 +499,11 @@ export class StateService<
) ;
) ;
}
}
@withPrototype ( SymmetricCryptoKey , SymmetricCryptoKey . fromJSON )
async getCryptoMasterKey ( options? : StorageOptions ) : Promise < SymmetricCryptoKey > {
async getCryptoMasterKey ( options? : StorageOptions ) : Promise < SymmetricCryptoKey > {
return (
const account = await this . getAccount (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ? . keys ? . cryptoMasterKey ;
) ;
return account ? . keys ? . cryptoMasterKey ;
}
}
async setCryptoMasterKey ( value : SymmetricCryptoKey , options? : StorageOptions ) : Promise < void > {
async setCryptoMasterKey ( value : SymmetricCryptoKey , options? : StorageOptions ) : Promise < void > {
@ -604,23 +609,6 @@ export class StateService<
await this . saveSecureStorageKey ( partialKeys . biometricKey , value , options ) ;
await this . saveSecureStorageKey ( partialKeys . biometricKey , value , options ) ;
}
}
async getDecodedToken ( options? : StorageOptions ) : Promise < any > {
return (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
) ? . tokens ? . decodedToken ;
}
async setDecodedToken ( value : any , options? : StorageOptions ) : Promise < void > {
const account = await this . getAccount (
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
account . tokens . decodedToken = value ;
await this . saveAccount (
account ,
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
}
@withPrototypeForArrayMembers ( CipherView , CipherView . fromJSON )
@withPrototypeForArrayMembers ( CipherView , CipherView . fromJSON )
async getDecryptedCiphers ( options? : StorageOptions ) : Promise < CipherView [ ] > {
async getDecryptedCiphers ( options? : StorageOptions ) : Promise < CipherView [ ] > {
return (
return (
@ -657,11 +645,11 @@ export class StateService<
) ;
) ;
}
}
@withPrototype ( SymmetricCryptoKey , SymmetricCryptoKey . fromJSON )
async getDecryptedCryptoSymmetricKey ( options? : StorageOptions ) : Promise < SymmetricCryptoKey > {
async getDecryptedCryptoSymmetricKey ( options? : StorageOptions ) : Promise < SymmetricCryptoKey > {
return (
const account = await this . getAccount (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ? . keys ? . cryptoSymmetricKey ? . decrypted ;
) ;
return account ? . keys ? . cryptoSymmetricKey ? . decrypted ;
}
}
async setDecryptedCryptoSymmetricKey (
async setDecryptedCryptoSymmetricKey (
@ -678,14 +666,13 @@ export class StateService<
) ;
) ;
}
}
@withPrototypeForMap ( SymmetricCryptoKey , SymmetricCryptoKey . fromJSON )
async getDecryptedOrganizationKeys (
async getDecryptedOrganizationKeys (
options? : StorageOptions
options? : StorageOptions
) : Promise < Map < string , SymmetricCryptoKey > > {
) : Promise < Map < string , SymmetricCryptoKey > > {
const account = await this . getAccount (
const account = await this . getAccount (
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
return account ? . keys ? . organizationKeys ? . decrypted ;
return this . recordToMap ( account ? . keys ? . organizationKeys ? . decrypted ) ;
}
}
async setDecryptedOrganizationKeys (
async setDecryptedOrganizationKeys (
@ -695,7 +682,7 @@ export class StateService<
const account = await this . getAccount (
const account = await this . getAccount (
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
account . keys . organizationKeys . decrypted = value ;
account . keys . organizationKeys . decrypted = this . mapToRecord ( value ) ;
await this . saveAccount (
await this . saveAccount (
account ,
account ,
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
@ -725,7 +712,6 @@ export class StateService<
) ;
) ;
}
}
@withPrototype ( EncString )
async getDecryptedPinProtected ( options? : StorageOptions ) : Promise < EncString > {
async getDecryptedPinProtected ( options? : StorageOptions ) : Promise < EncString > {
return (
return (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
@ -762,14 +748,9 @@ export class StateService<
}
}
async getDecryptedPrivateKey ( options? : StorageOptions ) : Promise < ArrayBuffer > {
async getDecryptedPrivateKey ( options? : StorageOptions ) : Promise < ArrayBuffer > {
const privateKey = (
return (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
) ? . keys ? . privateKey ;
) ? . keys ? . privateKey . decrypted ;
let result = privateKey ? . decrypted ;
if ( result == null && privateKey ? . decryptedSerialized != null ) {
result = Utils . fromByteStringToArray ( privateKey . decryptedSerialized ) ;
}
return result ;
}
}
async setDecryptedPrivateKey ( value : ArrayBuffer , options? : StorageOptions ) : Promise < void > {
async setDecryptedPrivateKey ( value : ArrayBuffer , options? : StorageOptions ) : Promise < void > {
@ -777,21 +758,19 @@ export class StateService<
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
account . keys . privateKey . decrypted = value ;
account . keys . privateKey . decrypted = value ;
account . keys . privateKey . decryptedSerialized =
value == null ? null : Utils . fromBufferToByteString ( value ) ;
await this . saveAccount (
await this . saveAccount (
account ,
account ,
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
}
}
@withPrototypeForMap ( SymmetricCryptoKey , SymmetricCryptoKey . fromJSON )
async getDecryptedProviderKeys (
async getDecryptedProviderKeys (
options? : StorageOptions
options? : StorageOptions
) : Promise < Map < string , SymmetricCryptoKey > > {
) : Promise < Map < string , SymmetricCryptoKey > > {
return (
const account = await this . getAccount (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ? . keys ? . providerKeys ? . decrypted ;
) ;
return this . recordToMap ( account ? . keys ? . providerKeys ? . decrypted ) ;
}
}
async setDecryptedProviderKeys (
async setDecryptedProviderKeys (
@ -801,7 +780,7 @@ export class StateService<
const account = await this . getAccount (
const account = await this . getAccount (
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
account . keys . providerKeys . decrypted = value ;
account . keys . providerKeys . decrypted = this . mapToRecord ( value ) ;
await this . saveAccount (
await this . saveAccount (
account ,
account ,
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
@ -1538,7 +1517,6 @@ export class StateService<
) ;
) ;
}
}
@withPrototype ( EnvironmentUrls )
async getEnvironmentUrls ( options? : StorageOptions ) : Promise < EnvironmentUrls > {
async getEnvironmentUrls ( options? : StorageOptions ) : Promise < EnvironmentUrls > {
if ( ( await this . state ( ) ) ? . activeUserId == null ) {
if ( ( await this . state ( ) ) ? . activeUserId == null ) {
return await this . getGlobalEnvironmentUrls ( options ) ;
return await this . getGlobalEnvironmentUrls ( options ) ;
@ -2021,11 +1999,7 @@ export class StateService<
const keys = (
const keys = (
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
await this . getAccount ( this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) ) )
) ? . keys ;
) ? . keys ;
let result = keys ? . publicKey ;
return keys ? . publicKey ;
if ( result == null && keys ? . publicKeySerialized != null ) {
result = Utils . fromByteStringToArray ( keys . publicKeySerialized ) ;
}
return result ;
}
}
async setPublicKey ( value : ArrayBuffer , options? : StorageOptions ) : Promise < void > {
async setPublicKey ( value : ArrayBuffer , options? : StorageOptions ) : Promise < void > {
@ -2033,7 +2007,6 @@ export class StateService<
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
) ;
) ;
account . keys . publicKey = value ;
account . keys . publicKey = value ;
account . keys . publicKeySerialized = value == null ? null : Utils . fromBufferToByteString ( value ) ;
await this . saveAccount (
await this . saveAccount (
account ,
account ,
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
this . reconcileOptions ( options , await this . defaultInMemoryOptions ( ) )
@ -2741,8 +2714,11 @@ export class StateService<
: await this . secureStorageService . save ( ` ${ options . userId } ${ key } ` , value , options ) ;
: await this . secureStorageService . save ( ` ${ options . userId } ${ key } ` , value , options ) ;
}
}
protected state ( ) : Promise < State < TGlobalState , TAccount > > {
protected async state ( ) : Promise < State < TGlobalState , TAccount > > {
return this . memoryStorageService . get < State < TGlobalState , TAccount > > ( keys . state ) ;
const state = await this . memoryStorageService . get < State < TGlobalState , TAccount > > ( keys . state , {
deserializer : ( s ) = > State . fromJSON ( s ) ,
} ) ;
return state ;
}
}
private async setState ( state : State < TGlobalState , TAccount > ) : Promise < void > {
private async setState ( state : State < TGlobalState , TAccount > ) : Promise < void > {
@ -2761,6 +2737,14 @@ export class StateService<
await this . setState ( updatedState ) ;
await this . setState ( updatedState ) ;
} ) ;
} ) ;
}
}
private mapToRecord < V > ( map : Map < string , V > ) : Record < string , V > {
return map == null ? null : Object . fromEntries ( map ) ;
}
private recordToMap < V > ( record : Record < string , V > ) : Map < string , V > {
return record == null ? null : new Map ( Object . entries ( record ) ) ;
}
}
}
export function withPrototype < T > (
export function withPrototype < T > (
@ -2893,52 +2877,3 @@ function withPrototypeForObjectValues<T>(
} ;
} ;
} ;
} ;
}
}
function withPrototypeForMap < T > (
valuesConstructor : new ( . . . args : any [ ] ) = > T ,
valuesConverter : ( input : any ) = > T = ( i ) = > i
) : (
target : any ,
propertyKey : string | symbol ,
descriptor : PropertyDescriptor
) = > { value : ( . . . args : any [ ] ) = > Promise < Map < string , T > > } {
return ( target : any , propertyKey : string | symbol , descriptor : PropertyDescriptor ) = > {
const originalMethod = descriptor . value ;
return {
value : function ( . . . args : any [ ] ) {
const originalResult : Promise < any > = originalMethod . apply ( this , args ) ;
if ( ! ( originalResult instanceof Promise ) ) {
throw new Error (
` Error applying prototype to stored value -- result is not a promise for method ${ String (
propertyKey
) } `
) ;
}
return originalResult . then ( ( result ) = > {
if ( result == null ) {
return null ;
} else if ( result instanceof Map ) {
return result ;
} else {
for ( const key in Object . keys ( result ) ) {
result [ key ] =
result [ key ] == null ||
result [ key ] . constructor . name === valuesConstructor . prototype . constructor . name
? valuesConverter ( result [ key ] )
: valuesConverter (
Object . create (
valuesConstructor . prototype ,
Object . getOwnPropertyDescriptors ( result [ key ] )
)
) ;
}
return new Map < string , T > ( Object . entries ( result ) ) ;
}
} ) ;
} ,
} ;
} ;
}