1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-24 00:23:17 +00:00

[PM-30301][PM-30302] Use SDK for Create and Update cipher operations (#18149)

* Migrate create and edit operations to use SDK for ciphers

* WIP: Adds admin call to edit ciphers with SDK

* Add client version to SDK intialization settings

* Remove console.log statements

* Adds originalCipherId and collectionIds to updateCipher

* Update tests for new cipehrService interfaces

* Rename SdkCipherOperations feature flag

* Add call to Admin edit SDK if flag is passed

* Add tests for SDK path

* Revert changes to .npmrc

* Remove outdated comments

* Fix feature flag name

* Fix UUID format in cipher.service.spec.ts

* Update calls to cipherService.updateWithServer and .createWithServer to new interface

* Update CLI and Desktop to use new cipherSErvice interfaces

* Fix tests for new cipherService interface change

* Bump sdk-internal and commercial-sdk-internal versions to 0.2.0-main.439

* Fix linting errors

* Fix typescript errors impacted by this chnage

* Fix caching issue on browser extension when using SDK cipher ops.

* Remove commented code

* Fix bug causing race condition due to not consuming / awaiting observable.

* Add missing 'await' to decrypt call

* Clean up unnecessary else statements and fix function naming

* Add comments for this.clearCache

* Add tests for SDK CipherView conversion functions

* Replace sdkservice with cipher-sdk.service

* Fix import issues in browser

* Fix import issues in cli

* Fix type issues

* Fix type issues

* Fix type issues

* Fix test that fails sporadically due to timing issue
This commit is contained in:
Nik Gilmore
2026-01-26 11:43:35 -08:00
committed by GitHub
parent 87555eaabd
commit 06c8c7316d
28 changed files with 1126 additions and 125 deletions

View File

@@ -254,17 +254,17 @@ describe("FidoAuthenticatorService", () => {
}
it("should save credential to vault if request confirmed by user", async () => {
const encryptedCipher = Symbol();
userInterfaceSession.confirmNewCredential.mockResolvedValue({
cipherId: existingCipher.id,
userVerified: false,
});
cipherService.encrypt.mockResolvedValue(encryptedCipher as unknown as EncryptionContext);
await authenticator.makeCredential(params, windowReference);
const saved = cipherService.encrypt.mock.lastCall?.[0];
expect(saved).toEqual(
const savedCipher = cipherService.updateWithServer.mock.lastCall?.[0];
const actualUserId = cipherService.updateWithServer.mock.lastCall?.[1];
expect(actualUserId).toEqual(userId);
expect(savedCipher).toEqual(
expect.objectContaining({
type: CipherType.Login,
name: existingCipher.name,
@@ -288,7 +288,6 @@ describe("FidoAuthenticatorService", () => {
}),
}),
);
expect(cipherService.updateWithServer).toHaveBeenCalledWith(encryptedCipher);
});
/** Spec: If the user does not consent or if user verification fails, return an error code equivalent to "NotAllowedError" and terminate the operation. */
@@ -361,17 +360,14 @@ describe("FidoAuthenticatorService", () => {
cipherService.getAllDecrypted.mockResolvedValue([await cipher]);
cipherService.decrypt.mockResolvedValue(cipher);
cipherService.encrypt.mockImplementation(async (cipher) => {
cipher.login.fido2Credentials[0].credentialId = credentialId; // Replace id for testability
return { cipher: {} as any as Cipher, encryptedFor: userId };
});
cipherService.createWithServer.mockImplementation(async ({ cipher }) => {
cipher.id = cipherId;
cipherService.createWithServer.mockImplementation(async (cipherView, _userId) => {
cipherView.id = cipherId;
return cipher;
});
cipherService.updateWithServer.mockImplementation(async ({ cipher }) => {
cipher.id = cipherId;
return cipher;
cipherService.updateWithServer.mockImplementation(async (cipherView, _userId) => {
cipherView.id = cipherId;
cipherView.login.fido2Credentials[0].credentialId = credentialId; // Replace id for testability
return cipherView;
});
});
@@ -701,14 +697,11 @@ describe("FidoAuthenticatorService", () => {
/** Spec: Increment the credential associated signature counter */
it("should increment counter and save to server when stored counter is larger than zero", async () => {
const encrypted = Symbol();
cipherService.encrypt.mockResolvedValue(encrypted as any);
ciphers[0].login.fido2Credentials[0].counter = 9000;
await authenticator.getAssertion(params, windowReference);
expect(cipherService.updateWithServer).toHaveBeenCalledWith(encrypted);
expect(cipherService.encrypt).toHaveBeenCalledWith(
expect(cipherService.updateWithServer).toHaveBeenCalledWith(
expect.objectContaining({
id: ciphers[0].id,
login: expect.objectContaining({
@@ -725,8 +718,6 @@ describe("FidoAuthenticatorService", () => {
/** Spec: Authenticators that do not implement a signature counter leave the signCount in the authenticator data constant at zero. */
it("should not save to server when stored counter is zero", async () => {
const encrypted = Symbol();
cipherService.encrypt.mockResolvedValue(encrypted as any);
ciphers[0].login.fido2Credentials[0].counter = 0;
await authenticator.getAssertion(params, windowReference);

View File

@@ -187,8 +187,7 @@ export class Fido2AuthenticatorService<
if (Utils.isNullOrEmpty(cipher.login.username)) {
cipher.login.username = fido2Credential.userName;
}
const reencrypted = await this.cipherService.encrypt(cipher, activeUserId);
await this.cipherService.updateWithServer(reencrypted);
await this.cipherService.updateWithServer(cipher, activeUserId);
await this.cipherService.clearCache(activeUserId);
credentialId = fido2Credential.credentialId;
} catch (error) {
@@ -328,8 +327,7 @@ export class Fido2AuthenticatorService<
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(getUserId),
);
const encrypted = await this.cipherService.encrypt(selectedCipher, activeUserId);
await this.cipherService.updateWithServer(encrypted);
await this.cipherService.updateWithServer(selectedCipher, activeUserId);
await this.cipherService.clearCache(activeUserId);
}

View File

@@ -80,7 +80,7 @@ export class DefaultSdkService implements SdkService {
client$ = this.environmentService.environment$.pipe(
concatMap(async (env) => {
await SdkLoadService.Ready;
const settings = this.toSettings(env);
const settings = await this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(this.apiService),
settings,
@@ -210,7 +210,7 @@ export class DefaultSdkService implements SdkService {
return undefined;
}
const settings = this.toSettings(env);
const settings = await this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(this.apiService, userId),
settings,
@@ -322,11 +322,12 @@ export class DefaultSdkService implements SdkService {
client.platform().load_flags(featureFlagMap);
}
private toSettings(env: Environment): ClientSettings {
private async toSettings(env: Environment): Promise<ClientSettings> {
return {
apiUrl: env.getApiUrl(),
identityUrl: env.getIdentityUrl(),
deviceType: toSdkDevice(this.platformUtilsService.getDevice()),
bitwardenClientVersion: await this.platformUtilsService.getApplicationVersionNumber(),
userAgent: this.userAgent ?? navigator.userAgent,
};
}

View File

@@ -62,7 +62,7 @@ export class DefaultRegisterSdkService implements RegisterSdkService {
client$ = this.environmentService.environment$.pipe(
concatMap(async (env) => {
await SdkLoadService.Ready;
const settings = this.toSettings(env);
const settings = await this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(this.apiService),
settings,
@@ -137,7 +137,7 @@ export class DefaultRegisterSdkService implements RegisterSdkService {
return undefined;
}
const settings = this.toSettings(env);
const settings = await this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(this.apiService, userId),
settings,
@@ -185,12 +185,13 @@ export class DefaultRegisterSdkService implements RegisterSdkService {
client.platform().load_flags(featureFlagMap);
}
private toSettings(env: Environment): ClientSettings {
private async toSettings(env: Environment): Promise<ClientSettings> {
return {
apiUrl: env.getApiUrl(),
identityUrl: env.getIdentityUrl(),
deviceType: toSdkDevice(this.platformUtilsService.getDevice()),
userAgent: this.userAgent ?? navigator.userAgent,
bitwardenClientVersion: await this.platformUtilsService.getApplicationVersionNumber(),
};
}
}