mirror of
https://github.com/bitwarden/browser
synced 2026-02-13 06:54:07 +00:00
Update the sdk service to use accountCryptographicState
This commit is contained in:
@@ -838,7 +838,7 @@ export default class MainBackground {
|
||||
this.accountService,
|
||||
this.kdfConfigService,
|
||||
this.keyService,
|
||||
this.securityStateService,
|
||||
this.accountCryptographicStateService,
|
||||
this.apiService,
|
||||
this.stateProvider,
|
||||
this.configService,
|
||||
|
||||
@@ -653,7 +653,7 @@ export class ServiceContainer {
|
||||
this.accountService,
|
||||
this.kdfConfigService,
|
||||
this.keyService,
|
||||
this.securityStateService,
|
||||
this.accountCryptographicStateService,
|
||||
this.apiService,
|
||||
this.stateProvider,
|
||||
this.configService,
|
||||
|
||||
@@ -1651,7 +1651,7 @@ const safeProviders: SafeProvider[] = [
|
||||
AccountServiceAbstraction,
|
||||
KdfConfigService,
|
||||
KeyService,
|
||||
SecurityStateService,
|
||||
AccountCryptographicStateService,
|
||||
ApiServiceAbstraction,
|
||||
StateProvider,
|
||||
ConfigService,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject, firstValueFrom, of } from "rxjs";
|
||||
|
||||
import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management";
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
mockAccountInfoWith,
|
||||
} from "../../../../spec";
|
||||
import { ApiService } from "../../../abstractions/api.service";
|
||||
import { AccountCryptographicStateService } from "../../../key-management/account-cryptography/account-cryptographic-state.service";
|
||||
import { EncryptedString } from "../../../key-management/crypto/models/enc-string";
|
||||
import { UserId } from "../../../types/guid";
|
||||
import { UserKey } from "../../../types/key";
|
||||
@@ -44,7 +44,7 @@ describe("DefaultSdkService", () => {
|
||||
let platformUtilsService!: MockProxy<PlatformUtilsService>;
|
||||
let kdfConfigService!: MockProxy<KdfConfigService>;
|
||||
let keyService!: MockProxy<KeyService>;
|
||||
let securityStateService!: MockProxy<SecurityStateService>;
|
||||
let accountCryptographicStateService!: MockProxy<AccountCryptographicStateService>;
|
||||
let configService!: MockProxy<ConfigService>;
|
||||
let service!: DefaultSdkService;
|
||||
let accountService!: FakeAccountService;
|
||||
@@ -59,7 +59,7 @@ describe("DefaultSdkService", () => {
|
||||
platformUtilsService = mock<PlatformUtilsService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
keyService = mock<KeyService>();
|
||||
securityStateService = mock<SecurityStateService>();
|
||||
accountCryptographicStateService = mock<AccountCryptographicStateService>();
|
||||
apiService = mock<ApiService>();
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
@@ -78,7 +78,7 @@ describe("DefaultSdkService", () => {
|
||||
accountService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
securityStateService,
|
||||
accountCryptographicStateService,
|
||||
apiService,
|
||||
fakeStateProvider,
|
||||
configService,
|
||||
@@ -103,13 +103,16 @@ describe("DefaultSdkService", () => {
|
||||
keyService.userKey$
|
||||
.calledWith(userId)
|
||||
.mockReturnValue(of(new SymmetricCryptoKey(new Uint8Array(64)) as UserKey));
|
||||
keyService.userEncryptedPrivateKey$
|
||||
.calledWith(userId)
|
||||
.mockReturnValue(of("private-key" as EncryptedString));
|
||||
keyService.encryptedOrgKeys$.calledWith(userId).mockReturnValue(of({}));
|
||||
keyService.userSigningKey$.calledWith(userId).mockReturnValue(of(null));
|
||||
keyService.userSignedPublicKey$.calledWith(userId).mockReturnValue(of(null));
|
||||
securityStateService.accountSecurityState$.calledWith(userId).mockReturnValue(of(null));
|
||||
accountCryptographicStateService.accountCryptographicState$
|
||||
.calledWith(userId)
|
||||
.mockReturnValue(
|
||||
of({
|
||||
V1: {
|
||||
private_key: "private-key" as EncryptedString,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe("given no client override has been set for the user", () => {
|
||||
|
||||
@@ -30,8 +30,8 @@ import {
|
||||
|
||||
import { ApiService } from "../../../abstractions/api.service";
|
||||
import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service";
|
||||
import { AccountCryptographicStateService } from "../../../key-management/account-cryptography/account-cryptographic-state.service";
|
||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||
import { SecurityStateService } from "../../../key-management/security-state/abstractions/security-state.service";
|
||||
import { OrganizationId, UserId } from "../../../types/guid";
|
||||
import { Environment, EnvironmentService } from "../../abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "../../abstractions/platform-utils.service";
|
||||
@@ -103,7 +103,7 @@ export class DefaultSdkService implements SdkService {
|
||||
private accountService: AccountService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
private keyService: KeyService,
|
||||
private securityStateService: SecurityStateService,
|
||||
private accountCryptographyStateService: AccountCryptographicStateService,
|
||||
private apiService: ApiService,
|
||||
private stateProvider: StateProvider,
|
||||
private configService: ConfigService,
|
||||
@@ -163,105 +163,70 @@ export class DefaultSdkService implements SdkService {
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
const kdfParams$ = this.kdfConfigService.getKdfConfig$(userId).pipe(distinctUntilChanged());
|
||||
const privateKey$ = this.keyService
|
||||
.userEncryptedPrivateKey$(userId)
|
||||
const accountCryptographicState$ = this.accountCryptographyStateService
|
||||
.accountCryptographicState$(userId)
|
||||
.pipe(distinctUntilChanged());
|
||||
const signingKey$ = this.keyService.userSigningKey$(userId).pipe(distinctUntilChanged());
|
||||
const userKey$ = this.keyService.userKey$(userId).pipe(distinctUntilChanged());
|
||||
const orgKeys$ = this.keyService.encryptedOrgKeys$(userId).pipe(
|
||||
distinctUntilChanged(compareValues), // The upstream observable emits different objects with the same values
|
||||
);
|
||||
const securityState$ = this.securityStateService
|
||||
.accountSecurityState$(userId)
|
||||
.pipe(distinctUntilChanged(compareValues));
|
||||
const signedPublicKey$ = this.keyService
|
||||
.userSignedPublicKey$(userId)
|
||||
.pipe(distinctUntilChanged(compareValues));
|
||||
|
||||
const client$ = combineLatest([
|
||||
this.environmentService.getEnvironment$(userId),
|
||||
account$,
|
||||
kdfParams$,
|
||||
privateKey$,
|
||||
accountCryptographicState$,
|
||||
userKey$,
|
||||
signingKey$,
|
||||
orgKeys$,
|
||||
securityState$,
|
||||
signedPublicKey$,
|
||||
SdkLoadService.Ready, // Makes sure we wait (once) for the SDK to be loaded
|
||||
]).pipe(
|
||||
// switchMap is required to allow the clean-up logic to be executed when `combineLatest` emits a new value.
|
||||
switchMap(
|
||||
([
|
||||
env,
|
||||
account,
|
||||
kdfParams,
|
||||
privateKey,
|
||||
userKey,
|
||||
signingKey,
|
||||
orgKeys,
|
||||
securityState,
|
||||
signedPublicKey,
|
||||
]) => {
|
||||
// Create our own observable to be able to implement clean-up logic
|
||||
return new Observable<Rc<PasswordManagerClient>>((subscriber) => {
|
||||
const createAndInitializeClient = async () => {
|
||||
if (env == null || kdfParams == null || privateKey == null || userKey == null) {
|
||||
return undefined;
|
||||
}
|
||||
switchMap(([env, account, kdfParams, accountCryptographicState, userKey, orgKeys]) => {
|
||||
// Create our own observable to be able to implement clean-up logic
|
||||
return new Observable<Rc<PasswordManagerClient>>((subscriber) => {
|
||||
const createAndInitializeClient = async () => {
|
||||
if (
|
||||
env == null ||
|
||||
kdfParams == null ||
|
||||
accountCryptographicState == null ||
|
||||
userKey == null
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const settings = this.toSettings(env);
|
||||
const client = await this.sdkClientFactory.createSdkClient(
|
||||
new JsTokenProvider(this.apiService, userId),
|
||||
settings,
|
||||
);
|
||||
const settings = this.toSettings(env);
|
||||
const client = await this.sdkClientFactory.createSdkClient(
|
||||
new JsTokenProvider(this.apiService, userId),
|
||||
settings,
|
||||
);
|
||||
|
||||
let accountCryptographicState: WrappedAccountCryptographicState;
|
||||
if (signingKey != null && securityState != null && signedPublicKey != null) {
|
||||
accountCryptographicState = {
|
||||
V2: {
|
||||
private_key: privateKey,
|
||||
signing_key: signingKey,
|
||||
security_state: securityState,
|
||||
signed_public_key: signedPublicKey,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
accountCryptographicState = {
|
||||
V1: {
|
||||
private_key: privateKey,
|
||||
},
|
||||
};
|
||||
}
|
||||
await this.initializeClient(
|
||||
userId,
|
||||
client,
|
||||
account,
|
||||
kdfParams,
|
||||
userKey,
|
||||
accountCryptographicState,
|
||||
orgKeys,
|
||||
);
|
||||
|
||||
await this.initializeClient(
|
||||
userId,
|
||||
client,
|
||||
account,
|
||||
kdfParams,
|
||||
userKey,
|
||||
accountCryptographicState,
|
||||
orgKeys,
|
||||
);
|
||||
return client;
|
||||
};
|
||||
|
||||
return client;
|
||||
};
|
||||
let client: Rc<PasswordManagerClient> | undefined;
|
||||
createAndInitializeClient()
|
||||
.then((c) => {
|
||||
client = c === undefined ? undefined : new Rc(c);
|
||||
|
||||
let client: Rc<PasswordManagerClient> | undefined;
|
||||
createAndInitializeClient()
|
||||
.then((c) => {
|
||||
client = c === undefined ? undefined : new Rc(c);
|
||||
subscriber.next(client);
|
||||
})
|
||||
.catch((e) => {
|
||||
subscriber.error(e);
|
||||
});
|
||||
|
||||
subscriber.next(client);
|
||||
})
|
||||
.catch((e) => {
|
||||
subscriber.error(e);
|
||||
});
|
||||
|
||||
return () => client?.markForDisposal();
|
||||
});
|
||||
},
|
||||
),
|
||||
return () => client?.markForDisposal();
|
||||
});
|
||||
}),
|
||||
tap({ finalize: () => this.sdkClientCache.delete(userId) }),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user