mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 00:33:44 +00:00
Pm-10953/add-user-context-to-sync-replaces (#10627)
* Require userId for setting masterKeyEncryptedUserKey * Replace folders for specified user * Require userId for collection replace * Cipher Replace requires userId * Require UserId to update equivalent domains * Require userId for policy replace * sync state updates between fake state for better testing * Revert to public observable tests Since they now sync, we can test single-user updates impacting active user observables * Do not init fake states through sync Do not sync initial null values, that might wipe out already existing data. * Require userId for Send replace * Include userId for organization replace * Require userId for billing sync data * Require user Id for key connector sync data * Allow decode of token by userId * Require userId for synced key connector updates * Add userId to policy setting during organization invite accept * Fix cli * Handle null userId --------- Co-authored-by: bnagawiecki <107435978+bnagawiecki@users.noreply.github.com>
This commit is contained in:
@@ -133,7 +133,7 @@ export abstract class CipherService implements UserKeyRotationDataProvider<Ciphe
|
||||
* @returns A promise that resolves to a record of updated cipher store, keyed by their cipher ID. Returns all ciphers, not just those updated
|
||||
*/
|
||||
upsert: (cipher: CipherData | CipherData[]) => Promise<Record<CipherId, CipherData>>;
|
||||
replace: (ciphers: { [id: string]: CipherData }) => Promise<any>;
|
||||
replace: (ciphers: { [id: string]: CipherData }, userId: UserId) => Promise<any>;
|
||||
clear: (userId?: string) => Promise<void>;
|
||||
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
|
||||
delete: (id: string | string[]) => Promise<any>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { CollectionId } from "../../types/guid";
|
||||
import { CollectionId, UserId } from "../../types/guid";
|
||||
import { CollectionData } from "../models/data/collection.data";
|
||||
import { Collection } from "../models/domain/collection";
|
||||
import { TreeNode } from "../models/domain/tree-node";
|
||||
@@ -22,7 +22,7 @@ export abstract class CollectionService {
|
||||
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
|
||||
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
|
||||
upsert: (collection: CollectionData | CollectionData[]) => Promise<any>;
|
||||
replace: (collections: { [id: string]: CollectionData }) => Promise<any>;
|
||||
replace: (collections: { [id: string]: CollectionData }, userId: UserId) => Promise<any>;
|
||||
clear: (userId?: string) => Promise<void>;
|
||||
delete: (id: string | string[]) => Promise<any>;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export abstract class FolderService implements UserKeyRotationDataProvider<Folde
|
||||
|
||||
export abstract class InternalFolderService extends FolderService {
|
||||
upsert: (folder: FolderData | FolderData[]) => Promise<void>;
|
||||
replace: (folders: { [id: string]: FolderData }) => Promise<void>;
|
||||
replace: (folders: { [id: string]: FolderData }, userId: UserId) => Promise<void>;
|
||||
clear: (userId?: string) => Promise<void>;
|
||||
delete: (id: string | string[]) => Promise<any>;
|
||||
}
|
||||
|
||||
@@ -913,8 +913,8 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
});
|
||||
}
|
||||
|
||||
async replace(ciphers: { [id: string]: CipherData }): Promise<any> {
|
||||
await this.updateEncryptedCipherState(() => ciphers);
|
||||
async replace(ciphers: { [id: string]: CipherData }, userId: UserId): Promise<any> {
|
||||
await this.updateEncryptedCipherState(() => ciphers, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -924,15 +924,18 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
*/
|
||||
private async updateEncryptedCipherState(
|
||||
update: (current: Record<CipherId, CipherData>) => Record<CipherId, CipherData>,
|
||||
userId: UserId = null,
|
||||
): Promise<Record<CipherId, CipherData>> {
|
||||
const userId = await firstValueFrom(this.stateProvider.activeUserId$);
|
||||
userId ||= await firstValueFrom(this.stateProvider.activeUserId$);
|
||||
// Store that we should wait for an update to return any ciphers
|
||||
await this.ciphersExpectingUpdate.forceValue(true);
|
||||
await this.clearDecryptedCiphersState(userId);
|
||||
const [, updatedCiphers] = await this.encryptedCiphersState.update((current) => {
|
||||
const result = update(current ?? {});
|
||||
return result;
|
||||
});
|
||||
const updatedCiphers = await this.stateProvider
|
||||
.getUser(userId, ENCRYPTED_CIPHERS)
|
||||
.update((current) => {
|
||||
const result = update(current ?? {});
|
||||
return result;
|
||||
});
|
||||
return updatedCiphers;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,8 +184,10 @@ export class CollectionService implements CollectionServiceAbstraction {
|
||||
});
|
||||
}
|
||||
|
||||
async replace(collections: Record<CollectionId, CollectionData>): Promise<void> {
|
||||
await this.encryptedCollectionDataState.update(() => collections);
|
||||
async replace(collections: Record<CollectionId, CollectionData>, userId: UserId): Promise<void> {
|
||||
await this.stateProvider
|
||||
.getUser(userId, ENCRYPTED_COLLECTION_DATA_KEY)
|
||||
.update(() => collections);
|
||||
}
|
||||
|
||||
async clear(userId?: UserId): Promise<void> {
|
||||
|
||||
@@ -120,7 +120,7 @@ describe("Folder Service", () => {
|
||||
});
|
||||
|
||||
it("replace", async () => {
|
||||
await folderService.replace({ "2": folderData("2", "test 2") });
|
||||
await folderService.replace({ "2": folderData("2", "test 2") }, mockUserId);
|
||||
|
||||
expect(await firstValueFrom(folderService.folders$)).toEqual([
|
||||
{
|
||||
|
||||
@@ -111,12 +111,12 @@ export class FolderService implements InternalFolderServiceAbstraction {
|
||||
});
|
||||
}
|
||||
|
||||
async replace(folders: { [id: string]: FolderData }): Promise<void> {
|
||||
async replace(folders: { [id: string]: FolderData }, userId: UserId): Promise<void> {
|
||||
if (!folders) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.encryptedFoldersState.update(() => {
|
||||
await this.stateProvider.getUser(userId, FOLDER_ENCRYPTED_FOLDERS).update(() => {
|
||||
const newFolders: Record<string, FolderData> = { ...folders };
|
||||
return newFolders;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user