1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-12-05 09:14:28 +01:00
This commit is contained in:
Dave 2025-12-04 18:38:52 -06:00 committed by GitHub
commit 9f38fcec75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 22 additions and 4 deletions

View File

@ -200,8 +200,16 @@ const safeProviders: SafeProvider[] = [
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
// the TokenService having to inject the PlatformUtilsService which introduces a
// circular dependency on Desktop only.
//
// For Windows portable builds, we disable secure storage to ensure tokens are
// stored on disk (in bitwarden-appdata) rather than in Windows Credential
// Manager, making them portable across machines. This allows users to move the USB drive
// between computers while maintaining authentication.
//
// Note: Portable mode does not use secure storage for read/write/clear operations,
// preventing any collision with tokens from a regular desktop installation.
provide: SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE && !ipc.platform.isWindowsPortable,
}),
safeProvider({
provide: DEFAULT_VAULT_TIMEOUT,

View File

@ -17,6 +17,7 @@ import {
isFlatpak,
isMacAppStore,
isSnapStore,
isWindowsPortable,
isWindowsStore,
} from "../utils";
@ -128,6 +129,7 @@ export default {
isDev: isDev(),
isMacAppStore: isMacAppStore(),
isWindowsStore: isWindowsStore(),
isWindowsPortable: isWindowsPortable(),
isFlatpak: isFlatpak(),
isSnapStore: isSnapStore(),
isAppImage: isAppImage(),

View File

@ -445,13 +445,15 @@ export class TokenService implements TokenServiceAbstraction {
// we can't determine storage location w/out vaultTimeoutAction and vaultTimeout
// but we can simply clear all locations to avoid the need to require those parameters.
// When secure storage is supported, clear the encryption key from secure storage.
// When not supported (e.g., portable builds), tokens are stored on disk and this step is skipped.
if (this.platformSupportsSecureStorage) {
// Always clear the access token key when clearing the access token
// The next set of the access token will create a new access token key
// Always clear the access token key when clearing the access token.
// The next set of the access token will create a new access token key.
await this.clearAccessTokenKey(userId);
}
// Platform doesn't support secure storage, so use state provider implementation
// Clear tokens from disk storage (all platforms)
await this.singleUserStateProvider.get(userId, ACCESS_TOKEN_DISK).update((_) => null, {
shouldUpdate: (previousValue) => previousValue !== null,
});
@ -478,6 +480,9 @@ export class TokenService implements TokenServiceAbstraction {
return null;
}
// When platformSupportsSecureStorage=true, tokens on disk are encrypted and require
// decryption keys from secure storage. When false (e.g., portable builds), tokens are
// stored on disk.
if (this.platformSupportsSecureStorage) {
let accessTokenKey: AccessTokenKey;
try {
@ -1118,6 +1123,9 @@ export class TokenService implements TokenServiceAbstraction {
) {
return TokenStorageLocation.Memory;
} else {
// Secure storage (e.g., OS credential manager) is preferred when available.
// Desktop portable builds set platformSupportsSecureStorage=false to store tokens
// on disk for portability across machines.
if (useSecureStorage && this.platformSupportsSecureStorage) {
return TokenStorageLocation.SecureStorage;
}