[PM-31112] Local user data key state declaration (#19471)

* client managed state

* sdk upgrade

* bad cherry-pick
This commit is contained in:
Maciej Zieniuk 2026-03-11 11:19:38 +01:00 committed by GitHub
parent 8108a09701
commit 0465bb2fb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 76 additions and 26 deletions

View File

@ -0,0 +1,24 @@
import { SdkRecordMapper } from "@bitwarden/common/platform/services/sdk/client-managed-state";
import { UserKeyDefinition } from "@bitwarden/common/platform/state";
import { LocalUserDataKeyState } from "@bitwarden/sdk-internal";
import { LOCAL_USER_DATA_KEY } from "../platform/services/key-state/local-user-data-key.state";
import { LocalUserDataKey } from "./types";
export class LocalUserDataKeyRecordMapper implements SdkRecordMapper<
LocalUserDataKey,
LocalUserDataKeyState
> {
userKeyDefinition(): UserKeyDefinition<Record<string, LocalUserDataKey>> {
return LOCAL_USER_DATA_KEY;
}
toSdk(value: LocalUserDataKey): LocalUserDataKeyState {
return { wrapped_key: value } as LocalUserDataKeyState;
}
fromSdk(value: LocalUserDataKeyState): LocalUserDataKey {
return value.wrapped_key as LocalUserDataKey;
}
}

View File

@ -32,3 +32,8 @@ export type VerifyingKey = Opaque<string, "VerifyingKey">;
* A signed security state, encoded in base64.
*/
export type SignedSecurityState = Opaque<SdkSignedSecurityState, "SignedSecurityState">;
/**
* A local user data key, encrypted with a symmetric key.
*/
export type LocalUserDataKey = Opaque<EncString, "LocalUserDataKey">;

View File

@ -0,0 +1,11 @@
import { LocalUserDataKey } from "../../../key-management/types";
import { CRYPTO_DISK, UserKeyDefinition } from "../../state";
export const LOCAL_USER_DATA_KEY = UserKeyDefinition.record<LocalUserDataKey>(
CRYPTO_DISK,
"localUserDataKey",
{
deserializer: (obj) => obj,
clearOn: ["logout"],
},
);

View File

@ -2,12 +2,13 @@ import { firstValueFrom, map } from "rxjs";
import { UserId } from "@bitwarden/common/types/guid";
import { CipherRecordMapper } from "@bitwarden/common/vault/models/domain/cipher-sdk-mapper";
import { StateClient, Repository } from "@bitwarden/sdk-internal";
import { Repository, StateClient } from "@bitwarden/sdk-internal";
import { LocalUserDataKeyRecordMapper } from "../../../key-management/local-user-data-key-mapper";
import { UserKeyRecordMapper } from "../../../key-management/user-key-mapper";
import { StateProvider, UserKeyDefinition } from "../../state";
export async function initializeState(
export async function initializeClientManagedState(
userId: UserId,
stateClient: StateClient,
stateProvider: StateProvider,
@ -16,6 +17,11 @@ export async function initializeState(
cipher: new RepositoryRecord(userId, stateProvider, new CipherRecordMapper()),
folder: null,
user_key_state: new RepositoryRecord(userId, stateProvider, new UserKeyRecordMapper()),
local_user_data_key_state: new RepositoryRecord(
userId,
stateProvider,
new LocalUserDataKeyRecordMapper(),
),
});
}
@ -32,14 +38,6 @@ export class RepositoryRecord<ClientType, SdkType> implements Repository<SdkType
private mapper: SdkRecordMapper<ClientType, SdkType>,
) {}
private getUserState() {
return this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition());
}
private async getRecord(): Promise<Record<string, ClientType>> {
return await firstValueFrom(this.getUserState().state$.pipe(map((state) => state ?? {})));
}
async get(id: string): Promise<SdkType | null> {
const record = await this.getRecord();
const element = record[id];
@ -93,4 +91,12 @@ export class RepositoryRecord<ClientType, SdkType> implements Repository<SdkType
async removeAll(): Promise<void> {
await this.getUserState().update(() => ({}));
}
private getUserState() {
return this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition());
}
private async getRecord(): Promise<Record<string, ClientType>> {
return await firstValueFrom(this.getUserState().state$.pipe(map((state) => state ?? {})));
}
}

View File

@ -52,7 +52,7 @@ import { compareValues } from "../../misc/compare-values";
import { Rc } from "../../misc/reference-counting/rc";
import { StateProvider } from "../../state";
import { initializeState } from "./client-managed-state";
import { initializeClientManagedState } from "./client-managed-state";
// A symbol that represents an overridden client that is explicitly set to undefined,
// blocking the creation of an internal client for that user.
@ -252,8 +252,8 @@ export class DefaultSdkService implements SdkService {
accountCryptographicState: WrappedAccountCryptographicState,
orgKeys: Record<OrganizationId, EncString>,
) {
// Initialize the SDK managed database and the client managed repositories.
await initializeState(userId, client.platform().state(), this.stateProvider);
// Initialize the client managed repositories.
await initializeClientManagedState(userId, client.platform().state(), this.stateProvider);
await this.loadFeatureFlags(client);
if (await this.configService.getFeatureFlag(FeatureFlag.UnlockViaSDK)) {

View File

@ -29,7 +29,7 @@ import { toSdkDevice, UserNotLoggedInError } from "../../abstractions/sdk/sdk.se
import { Rc } from "../../misc/reference-counting/rc";
import { StateProvider } from "../../state";
import { initializeState } from "./client-managed-state";
import { initializeClientManagedState } from "./client-managed-state";
// A symbol that represents an overridden client that is explicitly set to undefined,
// blocking the creation of an internal client for that user.
@ -143,8 +143,12 @@ export class DefaultRegisterSdkService implements RegisterSdkService {
settings,
);
// Initialize the SDK managed database and the client managed repositories.
await initializeState(userId, client.platform().state(), this.stateProvider);
// Initialize the client managed repositories.
await initializeClientManagedState(
userId,
client.platform().state(),
this.stateProvider,
);
await this.loadFeatureFlags(client);

16
package-lock.json generated
View File

@ -23,8 +23,8 @@
"@angular/platform-browser": "20.3.17",
"@angular/platform-browser-dynamic": "20.3.17",
"@angular/router": "20.3.17",
"@bitwarden/commercial-sdk-internal": "0.2.0-main.579",
"@bitwarden/sdk-internal": "0.2.0-main.579",
"@bitwarden/commercial-sdk-internal": "0.2.0-main.589",
"@bitwarden/sdk-internal": "0.2.0-main.589",
"@electron/fuses": "1.8.0",
"@emotion/css": "11.13.5",
"@koa/multer": "4.0.0",
@ -4946,9 +4946,9 @@
"link": true
},
"node_modules/@bitwarden/commercial-sdk-internal": {
"version": "0.2.0-main.579",
"resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.579.tgz",
"integrity": "sha512-QZhDwEd/Y4fijqk2zpeH6z4ln8HE6XeKKqbN5asRtmlZFKcT9fT4xZy+u51QYlTZb8uqfVsQoVHiElL6JZYYng==",
"version": "0.2.0-main.589",
"resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.589.tgz",
"integrity": "sha512-+4qZ0gj71jOFepD0hIwhcuM/Eegf+JP1IbQmYA5YIA1Q5TBpms6sULcQZRTkJEokH8PiGH5xxvUk4k/XQAL2tQ==",
"license": "BITWARDEN SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT",
"dependencies": {
"type-fest": "^5.0.0"
@ -5054,9 +5054,9 @@
"link": true
},
"node_modules/@bitwarden/sdk-internal": {
"version": "0.2.0-main.579",
"resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.579.tgz",
"integrity": "sha512-bXRdhaBf/rtqdDFlhs7YQ0G8gN51ACUAPza/XpHx7cL+40CSr+hdzljnQPItaEtXdyNsAF71nMnLiTvGp2rVcg==",
"version": "0.2.0-main.589",
"resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.589.tgz",
"integrity": "sha512-PDygPFmu+t/GHHLZjKjWOnpFjck4pYRZArB4ZBuyh7rwWK1tX5brBWtZu38+pJPVTiBHy1D1TUwIHbWfeiS0Uw==",
"license": "GPL-3.0",
"dependencies": {
"type-fest": "^5.0.0"

View File

@ -165,8 +165,8 @@
"@angular/platform-browser": "20.3.17",
"@angular/platform-browser-dynamic": "20.3.17",
"@angular/router": "20.3.17",
"@bitwarden/commercial-sdk-internal": "0.2.0-main.579",
"@bitwarden/sdk-internal": "0.2.0-main.579",
"@bitwarden/commercial-sdk-internal": "0.2.0-main.589",
"@bitwarden/sdk-internal": "0.2.0-main.589",
"@electron/fuses": "1.8.0",
"@emotion/css": "11.13.5",
"@koa/multer": "4.0.0",