Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
769fe1b
fix: broken SDK interface
coroiu May 27, 2025
568ac8b
Fix all compile errors related to uuids
Hinton May 27, 2025
f638719
Merge branch 'main' of github.com:bitwarden/clients into arch/uuids
Hinton May 29, 2025
9f4cae8
Update usages of sdk to type-safe SDK type
quexten Jul 28, 2025
fdb038b
Update sdk version
quexten Jul 28, 2025
1660428
Merge branch 'main' into km/encstring-sdk
quexten Jul 28, 2025
f57c59f
Update to "toSdk"
quexten Jul 28, 2025
6315a46
Merge branch 'km/encstring-sdk' of github.com:bitwarden/clients into โ€ฆ
quexten Jul 28, 2025
7a9a614
Move pin service to km ownership
quexten Jul 29, 2025
e626314
Run format
quexten Jul 29, 2025
d7cdbcf
Eslint
quexten Jul 29, 2025
3ab3160
Fix tsconfig
quexten Jul 29, 2025
7320305
Fix imports and test
quexten Jul 29, 2025
93df2b1
Clean up imports
quexten Jul 29, 2025
f6f8949
Pin tmp
quexten Jul 30, 2025
6a6e8a1
Merge branch 'main' into km/encstring-sdk
quexten Jul 30, 2025
55dc331
Merge branch 'km/encstring-sdk' into km/new-pin-service-interface
quexten Jul 30, 2025
a149716
Initial version of updated pin service
quexten Jul 31, 2025
619688a
Add tests
quexten Jul 31, 2025
06fbb6e
Rename function
quexten Jul 31, 2025
49427c0
Merge branch 'main' into km/new-pin-service-interface
quexten Jul 31, 2025
300c172
Clean up logging
quexten Aug 1, 2025
e95f31b
Fix imports
quexten Aug 1, 2025
c05fa2a
Fix cli build
quexten Aug 1, 2025
30b7db7
Merge branch 'main' of github.com:bitwarden/clients into arch/uuids
Hinton Aug 22, 2025
77f4d00
Fix browser desktop
Hinton Aug 22, 2025
c4ff021
Fix tests
Hinton Aug 22, 2025
d57bac2
Merge main
quexten Aug 26, 2025
456b599
Attempt to fix
quexten Aug 26, 2025
412c161
Merge branch 'arch/uuids' into km/new-pin-service-interface
quexten Aug 26, 2025
b660568
Fix build
quexten Aug 26, 2025
7b53efb
Fix tests
quexten Aug 26, 2025
a497f8e
Fix browser build
quexten Aug 26, 2025
be01bcf
Merge branch 'main' into km/new-pin-service-interface
quexten Sep 1, 2025
4200d1a
Add missing empty line
quexten Sep 1, 2025
48fefd6
Fix linting
quexten Sep 1, 2025
50c4a5d
Remove non-required change
quexten Sep 1, 2025
c9a8889
Missing newline
quexten Sep 1, 2025
583d2b6
Re-add comment
quexten Sep 1, 2025
b26ae3e
Undo change to file
quexten Sep 1, 2025
22b5751
Fix missing empty line
quexten Sep 1, 2025
9f1f845
Cleanup
quexten Sep 1, 2025
507a574
Cleanup
quexten Sep 1, 2025
966205b
Cleanup
quexten Sep 1, 2025
200f8d4
Cleanup
quexten Sep 1, 2025
a95b501
Switch to replaysubject
quexten Sep 1, 2025
bcddc14
Add comments
quexten Sep 1, 2025
f2393c9
Fix tests
quexten Sep 1, 2025
81c2fd6
Run prettier
quexten Sep 1, 2025
3b44824
Undo change
quexten Sep 1, 2025
a1a45c0
Fix browser
quexten Sep 1, 2025
862e3f9
Merge branch 'main' into km/new-pin-service-interface
quexten Sep 1, 2025
6f3c67a
Fix circular dependency on browser
quexten Sep 1, 2025
d8c1632
Merge branch 'km/new-pin-service-interface' of github.com:bitwarden/cโ€ฆ
quexten Sep 1, 2025
2661dab
Add missing clear ephemeral pin
quexten Sep 3, 2025
5d92c4a
Address feedback
quexten Sep 3, 2025
ef959ba
Update docs
quexten Sep 3, 2025
2b4f681
Simplify sdk usage in pin service
quexten Sep 3, 2025
e1bd830
Replace with mock sdk
quexten Sep 3, 2025
46257e0
Merge branch 'main' into km/new-pin-service-interface
quexten Sep 3, 2025
68c237e
Update sdk
quexten Sep 3, 2025
257940c
Initialize pin service via unlock instead of listening to keyservice
quexten Sep 3, 2025
f0d4937
Cleanup
quexten Sep 3, 2025
e508480
Fix test
quexten Sep 3, 2025
aad2968
Prevent race condition with userkey not being set
quexten Sep 3, 2025
3cb6670
Filter null userkeys
quexten Sep 3, 2025
cb48240
Merge branch 'main' into km/new-pin-service-interface
quexten Sep 3, 2025
57115cb
Merge branch 'main' into km/new-pin-service-interface
jlf0dev Sep 25, 2025
fa9dcd0
Merge branch 'main' into km/new-pin-service-interface
quexten Sep 28, 2025
ad97210
[PM-24124] Pin State Service (#16641)
jlf0dev Oct 6, 2025
ac36d1a
Fix dep cycle
quexten Oct 8, 2025
73aee60
Fix tests and remaining build issues
quexten Oct 8, 2025
10b3d5a
Fix cli build
quexten Oct 8, 2025
813f9ca
Merge branch 'main' into km/new-pin-service-interface
quexten Oct 8, 2025
2aca230
Add comments about functions not being public API
quexten Oct 8, 2025
ac4da36
Merge branch 'km/new-pin-service-interface' of github.com:bitwarden/cโ€ฆ
quexten Oct 8, 2025
1e9b416
Merge branch 'main' into km/new-pin-service-interface
quexten Oct 13, 2025
528607a
Merge branch 'main' into km/new-pin-service-interface
quexten Oct 13, 2025
47a5e60
Merge branch 'main' into km/new-pin-service-interface
quexten Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,8 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
.pipe(
concatMap(async (value) => {
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
const pinKeyEncryptedUserKey =
(await this.pinService.getPinKeyEncryptedUserKeyPersistent(userId)) ||
(await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId));
await this.pinService.clearPinKeyEncryptedUserKeyPersistent(userId);
await this.pinService.clearPinKeyEncryptedUserKeyEphemeral(userId);
await this.pinService.storePinKeyEncryptedUserKey(pinKeyEncryptedUserKey, value, userId);
const pin = await this.pinService.getPin(userId);
await this.pinService.setPin(pin, value ? "EPHEMERAL" : "PERSISTENT", userId);
this.refreshTimeoutSettings$.next();
}),
takeUntil(this.destroy$),
Expand Down Expand Up @@ -486,7 +482,7 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
}
} else {
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.vaultTimeoutSettingsService.clear(userId);
await this.pinService.unsetPin(userId);
}
}

Expand Down
30 changes: 17 additions & 13 deletions apps/browser/src/background/main.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarde
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/services/key-connector.service";
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { MasterPasswordService } from "@bitwarden/common/key-management/master-password/services/master-password.service";
import { PinStateService } from "@bitwarden/common/key-management/pin/pin-state.service.implementation";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { PinService } from "@bitwarden/common/key-management/pin/pin.service.implementation";
import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service";
Expand Down Expand Up @@ -706,18 +707,7 @@ export default class MainBackground {

this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider);

this.pinService = new PinService(
this.accountService,
this.cryptoFunctionService,
this.encryptService,
this.kdfConfigService,
this.keyGenerationService,
this.logService,
this.stateProvider,
);

this.keyService = new DefaultKeyService(
this.pinService,
this.masterPasswordService,
this.keyGenerationService,
this.cryptoFunctionService,
Expand All @@ -730,6 +720,19 @@ export default class MainBackground {
this.kdfConfigService,
);

const pinStateService = new PinStateService(this.stateProvider);

this.pinService = new PinService(
this.accountService,
this.encryptService,
this.kdfConfigService,
this.keyGenerationService,
this.logService,
this.keyService,
this.sdkService,
pinStateService,
);

this.appIdService = new AppIdService(this.storageService, this.logService);

this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
Expand All @@ -738,7 +741,7 @@ export default class MainBackground {

this.vaultTimeoutSettingsService = new DefaultVaultTimeoutSettingsService(
this.accountService,
this.pinService,
pinStateService,
this.userDecryptionOptionsService,
this.keyService,
this.tokenService,
Expand All @@ -756,6 +759,7 @@ export default class MainBackground {
this.biometricStateService,
this.messagingService,
this.vaultTimeoutSettingsService,
this.pinService,
);

this.apiService = new ApiService(
Expand Down Expand Up @@ -1676,9 +1680,9 @@ export default class MainBackground {
this.cipherService.clear(userBeingLoggedOut),
// ! DO NOT REMOVE folderService.clear ! For more information see PM-25660
this.folderService.clear(userBeingLoggedOut),
this.vaultTimeoutSettingsService.clear(userBeingLoggedOut),
this.biometricStateService.logout(userBeingLoggedOut),
this.popupViewCacheBackgroundService.clearState(),
this.pinService.logout(userBeingLoggedOut),
/* We intentionally do not clear:
* - autofillSettingsService
* - badgeSettingsService
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { mock } from "jest-mock-extended";

import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
Expand All @@ -18,6 +19,7 @@ describe("background browser biometrics service tests", function () {
const biometricStateService = mock<BiometricStateService>();
const messagingService = mock<MessagingService>();
const vaultTimeoutSettingsService = mock<VaultTimeoutSettingsService>();
const pinService = mock<PinServiceAbstraction>();

beforeEach(() => {
jest.resetAllMocks();
Expand All @@ -28,6 +30,7 @@ describe("background browser biometrics service tests", function () {
biometricStateService,
messagingService,
vaultTimeoutSettingsService,
pinService,
);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { combineLatest, timer } from "rxjs";
import { filter, concatMap } from "rxjs/operators";

import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
Expand Down Expand Up @@ -29,6 +30,7 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
private biometricStateService: BiometricStateService,
private messagingService: MessagingService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
private pinService: PinServiceAbstraction,
) {
super();
// Always connect to the native messaging background if biometrics are enabled, not just when it is used
Expand Down Expand Up @@ -101,6 +103,7 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
if (await this.keyService.validateUserKey(userKey, userId)) {
await this.biometricStateService.setBiometricUnlockEnabled(true);
await this.keyService.setUserKey(userKey, userId);
await this.pinService.userUnlocked(userId);
// to update badge and other things
this.messagingService.send("switchAccount", { userId });
return userKey;
Expand Down
4 changes: 0 additions & 4 deletions apps/browser/src/popup/services/services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ import {
InternalMasterPasswordServiceAbstraction,
MasterPasswordServiceAbstraction,
} from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import {
VaultTimeoutService,
VaultTimeoutStringType,
Expand Down Expand Up @@ -271,7 +270,6 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: KeyService,
useFactory: (
pinService: PinServiceAbstraction,
masterPasswordService: InternalMasterPasswordServiceAbstraction,
keyGenerationService: KeyGenerationService,
cryptoFunctionService: CryptoFunctionService,
Expand All @@ -284,7 +282,6 @@ const safeProviders: SafeProvider[] = [
kdfConfigService: KdfConfigService,
) => {
const keyService = new DefaultKeyService(
pinService,
masterPasswordService,
keyGenerationService,
cryptoFunctionService,
Expand All @@ -300,7 +297,6 @@ const safeProviders: SafeProvider[] = [
return keyService;
},
deps: [
PinServiceAbstraction,
InternalMasterPasswordServiceAbstraction,
KeyGenerationService,
CryptoFunctionService,
Expand Down
30 changes: 16 additions & 14 deletions apps/cli/src/service-container/service-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import { MasterPasswordUnlockService } from "@bitwarden/common/key-management/ma
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { DefaultMasterPasswordUnlockService } from "@bitwarden/common/key-management/master-password/services/default-master-password-unlock.service";
import { MasterPasswordService } from "@bitwarden/common/key-management/master-password/services/master-password.service";
import { PinStateService } from "@bitwarden/common/key-management/pin/pin-state.service.implementation";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { PinService } from "@bitwarden/common/key-management/pin/pin.service.implementation";
import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service";
Expand All @@ -93,7 +94,7 @@ import {
} from "@bitwarden/common/platform/abstractions/environment.service";
import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { KeySuffixOptions, LogLevelType } from "@bitwarden/common/platform/enums";
import { LogLevelType } from "@bitwarden/common/platform/enums";
import { MessageSender } from "@bitwarden/common/platform/messaging";
import {
TaskSchedulerService,
Expand Down Expand Up @@ -459,18 +460,7 @@ export class ServiceContainer {
this.accountService,
);

this.pinService = new PinService(
this.accountService,
this.cryptoFunctionService,
this.encryptService,
this.kdfConfigService,
this.keyGenerationService,
this.logService,
this.stateProvider,
);

this.keyService = new KeyService(
this.pinService,
this.masterPasswordService,
this.keyGenerationService,
this.cryptoFunctionService,
Expand All @@ -483,6 +473,18 @@ export class ServiceContainer {
this.kdfConfigService,
);

const pinStateService = new PinStateService(this.stateProvider);
this.pinService = new PinService(
this.accountService,
this.encryptService,
this.kdfConfigService,
this.keyGenerationService,
this.logService,
this.keyService,
this.sdkService,
pinStateService,
);

this.masterPasswordUnlockService = new DefaultMasterPasswordUnlockService(
this.masterPasswordService,
this.keyService,
Expand All @@ -506,7 +508,7 @@ export class ServiceContainer {

this.vaultTimeoutSettingsService = new DefaultVaultTimeoutSettingsService(
this.accountService,
this.pinService,
pinStateService,
this.userDecryptionOptionsService,
this.keyService,
this.tokenService,
Expand Down Expand Up @@ -772,7 +774,7 @@ export class ServiceContainer {
this.folderApiService = new FolderApiService(this.folderService, this.apiService);

const lockedCallback = async (userId: UserId) =>
await this.keyService.clearStoredUserKey(KeySuffixOptions.Auto, userId);
await this.keyService.clearStoredUserKey(userId);

this.userVerificationApiService = new UserVerificationApiService(this.apiService);

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/accounts/settings.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ describe("SettingsComponent", () => {
await component.updatePinHandler(false);

expect(component.form.controls.pin.value).toBe(false);
expect(vaultTimeoutSettingsService.clear).toHaveBeenCalled();
expect(vaultTimeoutSettingsService.clear).not.toHaveBeenCalled();
expect(messagingService.send).toHaveBeenCalledWith("redrawMenu");
});
});
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/accounts/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.form.controls.pin.setValue(this.userHasPinSet, { emitEvent: false });
} else {
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.vaultTimeoutSettingsService.clear(userId);
await this.pinService.unsetPin(userId);
}
}

Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import {
VaultTimeout,
VaultTimeoutAction,
Expand Down Expand Up @@ -177,6 +178,7 @@ export class AppComponent implements OnInit, OnDestroy {
private readonly destroyRef: DestroyRef,
private readonly documentLangSetter: DocumentLangSetter,
private restrictedItemTypesService: RestrictedItemTypesService,
private pinService: PinServiceAbstraction,
private readonly tokenService: TokenService,
private desktopAutotypeDefaultSettingPolicy: DesktopAutotypeDefaultSettingPolicy,
) {
Expand Down Expand Up @@ -693,8 +695,8 @@ export class AppComponent implements OnInit, OnDestroy {
await this.cipherService.clear(userBeingLoggedOut);
// ! DO NOT REMOVE folderService.clear ! For more information see PM-25660
await this.folderService.clear(userBeingLoggedOut);
await this.vaultTimeoutSettingsService.clear(userBeingLoggedOut);
await this.biometricStateService.logout(userBeingLoggedOut);
await this.pinService.logout(userBeingLoggedOut);

await this.stateEventRunnerService.handleEvent("logout", userBeingLoggedOut);

Expand Down
1 change: 0 additions & 1 deletion apps/desktop/src/app/services/services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ const safeProviders: SafeProvider[] = [
provide: KeyServiceAbstraction,
useClass: ElectronKeyService,
deps: [
PinServiceAbstraction,
InternalMasterPasswordServiceAbstraction,
KeyGenerationService,
CryptoFunctionServiceAbstraction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { KeyGenerationService } from "@bitwarden/common/key-management/crypto";
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
Expand All @@ -26,7 +25,6 @@ import { ElectronKeyService } from "./electron-key.service";
describe("ElectronKeyService", () => {
let keyService: ElectronKeyService;

const pinService = mock<PinServiceAbstraction>();
const keyGenerationService = mock<KeyGenerationService>();
const cryptoFunctionService = mock<CryptoFunctionService>();
const encryptService = mock<EncryptService>();
Expand All @@ -48,7 +46,6 @@ describe("ElectronKeyService", () => {
stateProvider = new FakeStateProvider(accountService);

keyService = new ElectronKeyService(
pinService,
masterPasswordService,
keyGenerationService,
cryptoFunctionService,
Expand Down
7 changes: 0 additions & 7 deletions apps/desktop/src/key-management/electron-key.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { KeyGenerationService } from "@bitwarden/common/key-management/crypto";
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
Expand All @@ -22,7 +21,6 @@ import { DesktopBiometricsService } from "./biometrics/desktop.biometrics.servic
// TODO Remove this class once biometric client key half storage is moved https://bitwarden.atlassian.net/browse/PM-22342
export class ElectronKeyService extends DefaultKeyService {
constructor(
pinService: PinServiceAbstraction,
masterPasswordService: InternalMasterPasswordServiceAbstraction,
keyGenerationService: KeyGenerationService,
cryptoFunctionService: CryptoFunctionService,
Expand All @@ -37,7 +35,6 @@ export class ElectronKeyService extends DefaultKeyService {
private biometricService: DesktopBiometricsService,
) {
super(
pinService,
masterPasswordService,
keyGenerationService,
cryptoFunctionService,
Expand All @@ -51,10 +48,6 @@ export class ElectronKeyService extends DefaultKeyService {
);
}

override async clearStoredUserKey(keySuffix: KeySuffixOptions, userId: UserId): Promise<void> {
await super.clearStoredUserKey(keySuffix, userId);
}

protected override async storeAdditionalKeys(key: UserKey, userId: UserId) {
await super.storeAdditionalKeys(key, userId);

Expand Down
Loading
Loading