mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-20032] Give option to skip token refresh on fullSync (#14423)
* Give option to skip token refresh on fullSync * Fix listener
This commit is contained in:
@@ -8,6 +8,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { MessageListener, MessageSender } from "@bitwarden/common/platform/messaging";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SyncOptions } from "@bitwarden/common/platform/sync/sync.service";
|
||||
import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
@@ -80,7 +81,72 @@ describe("ForegroundSyncService", () => {
|
||||
const fullSyncPromise = sut.fullSync(true, false);
|
||||
expect(sut.syncInProgress).toBe(true);
|
||||
|
||||
const requestId = getAndAssertRequestId({ forceSync: true, allowThrowOnError: false });
|
||||
const requestId = getAndAssertRequestId({
|
||||
forceSync: true,
|
||||
options: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
});
|
||||
|
||||
// Pretend the sync has finished
|
||||
messages.next({ successfully: true, errorMessage: null, requestId: requestId });
|
||||
|
||||
const result = await fullSyncPromise;
|
||||
|
||||
expect(sut.syncInProgress).toBe(false);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
const testData: {
|
||||
input: boolean | SyncOptions | undefined;
|
||||
normalized: Required<SyncOptions>;
|
||||
}[] = [
|
||||
{
|
||||
input: undefined,
|
||||
normalized: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: true,
|
||||
normalized: { allowThrowOnError: true, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: false,
|
||||
normalized: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: false },
|
||||
normalized: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: true },
|
||||
normalized: { allowThrowOnError: true, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
normalized: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: true, skipTokenRefresh: false },
|
||||
normalized: { allowThrowOnError: true, skipTokenRefresh: false },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: true, skipTokenRefresh: true },
|
||||
normalized: { allowThrowOnError: true, skipTokenRefresh: true },
|
||||
},
|
||||
{
|
||||
input: { allowThrowOnError: false, skipTokenRefresh: true },
|
||||
normalized: { allowThrowOnError: false, skipTokenRefresh: true },
|
||||
},
|
||||
];
|
||||
|
||||
it.each(testData)("normalize input $input options correctly", async ({ input, normalized }) => {
|
||||
const messages = new Subject<FullSyncFinishedMessage>();
|
||||
messageListener.messages$.mockReturnValue(messages);
|
||||
const fullSyncPromise = sut.fullSync(true, input);
|
||||
expect(sut.syncInProgress).toBe(true);
|
||||
|
||||
const requestId = getAndAssertRequestId({
|
||||
forceSync: true,
|
||||
options: normalized,
|
||||
});
|
||||
|
||||
// Pretend the sync has finished
|
||||
messages.next({ successfully: true, errorMessage: null, requestId: requestId });
|
||||
@@ -97,7 +163,10 @@ describe("ForegroundSyncService", () => {
|
||||
const fullSyncPromise = sut.fullSync(false, false);
|
||||
expect(sut.syncInProgress).toBe(true);
|
||||
|
||||
const requestId = getAndAssertRequestId({ forceSync: false, allowThrowOnError: false });
|
||||
const requestId = getAndAssertRequestId({
|
||||
forceSync: false,
|
||||
options: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
});
|
||||
|
||||
// Pretend the sync has finished
|
||||
messages.next({
|
||||
@@ -118,7 +187,10 @@ describe("ForegroundSyncService", () => {
|
||||
const fullSyncPromise = sut.fullSync(true, true);
|
||||
expect(sut.syncInProgress).toBe(true);
|
||||
|
||||
const requestId = getAndAssertRequestId({ forceSync: true, allowThrowOnError: true });
|
||||
const requestId = getAndAssertRequestId({
|
||||
forceSync: true,
|
||||
options: { allowThrowOnError: true, skipTokenRefresh: false },
|
||||
});
|
||||
|
||||
// Pretend the sync has finished
|
||||
messages.next({
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { CoreSyncService } from "@bitwarden/common/platform/sync/internal";
|
||||
import { SyncOptions } from "@bitwarden/common/platform/sync/sync.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -22,7 +23,7 @@ import { InternalFolderService } from "@bitwarden/common/vault/abstractions/fold
|
||||
|
||||
import { FULL_SYNC_FINISHED } from "./sync-service.listener";
|
||||
|
||||
export type FullSyncMessage = { forceSync: boolean; allowThrowOnError: boolean; requestId: string };
|
||||
export type FullSyncMessage = { forceSync: boolean; options: SyncOptions; requestId: string };
|
||||
|
||||
export const DO_FULL_SYNC = new CommandDefinition<FullSyncMessage>("doFullSync");
|
||||
|
||||
@@ -60,9 +61,20 @@ export class ForegroundSyncService extends CoreSyncService {
|
||||
);
|
||||
}
|
||||
|
||||
async fullSync(forceSync: boolean, allowThrowOnError: boolean = false): Promise<boolean> {
|
||||
async fullSync(
|
||||
forceSync: boolean,
|
||||
allowThrowOnErrorOrOptions?: boolean | SyncOptions,
|
||||
): Promise<boolean> {
|
||||
this.syncInProgress = true;
|
||||
try {
|
||||
// Normalize options
|
||||
const options =
|
||||
typeof allowThrowOnErrorOrOptions === "boolean"
|
||||
? { allowThrowOnError: allowThrowOnErrorOrOptions, skipTokenRefresh: false }
|
||||
: {
|
||||
allowThrowOnError: allowThrowOnErrorOrOptions?.allowThrowOnError ?? false,
|
||||
skipTokenRefresh: allowThrowOnErrorOrOptions?.skipTokenRefresh ?? false,
|
||||
};
|
||||
const requestId = Utils.newGuid();
|
||||
const syncCompletedPromise = firstValueFrom(
|
||||
this.messageListener.messages$(FULL_SYNC_FINISHED).pipe(
|
||||
@@ -79,10 +91,10 @@ export class ForegroundSyncService extends CoreSyncService {
|
||||
}),
|
||||
),
|
||||
);
|
||||
this.messageSender.send(DO_FULL_SYNC, { forceSync, allowThrowOnError, requestId });
|
||||
this.messageSender.send(DO_FULL_SYNC, { forceSync, options, requestId });
|
||||
const result = await syncCompletedPromise;
|
||||
|
||||
if (allowThrowOnError && result.errorMessage != null) {
|
||||
if (options.allowThrowOnError && result.errorMessage != null) {
|
||||
throw new Error(result.errorMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,18 @@ describe("SyncServiceListener", () => {
|
||||
const emissionPromise = firstValueFrom(listener);
|
||||
|
||||
syncService.fullSync.mockResolvedValueOnce(value);
|
||||
messages.next({ forceSync: true, allowThrowOnError: false, requestId: "1" });
|
||||
messages.next({
|
||||
forceSync: true,
|
||||
options: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
requestId: "1",
|
||||
});
|
||||
|
||||
await emissionPromise;
|
||||
|
||||
expect(syncService.fullSync).toHaveBeenCalledWith(true, false);
|
||||
expect(syncService.fullSync).toHaveBeenCalledWith(true, {
|
||||
allowThrowOnError: false,
|
||||
skipTokenRefresh: false,
|
||||
});
|
||||
expect(messageSender.send).toHaveBeenCalledWith(FULL_SYNC_FINISHED, {
|
||||
successfully: value,
|
||||
errorMessage: null,
|
||||
@@ -45,11 +52,18 @@ describe("SyncServiceListener", () => {
|
||||
const emissionPromise = firstValueFrom(listener);
|
||||
|
||||
syncService.fullSync.mockRejectedValueOnce(new Error("SyncError"));
|
||||
messages.next({ forceSync: true, allowThrowOnError: false, requestId: "1" });
|
||||
messages.next({
|
||||
forceSync: true,
|
||||
options: { allowThrowOnError: false, skipTokenRefresh: false },
|
||||
requestId: "1",
|
||||
});
|
||||
|
||||
await emissionPromise;
|
||||
|
||||
expect(syncService.fullSync).toHaveBeenCalledWith(true, false);
|
||||
expect(syncService.fullSync).toHaveBeenCalledWith(true, {
|
||||
allowThrowOnError: false,
|
||||
skipTokenRefresh: false,
|
||||
});
|
||||
expect(messageSender.send).toHaveBeenCalledWith(FULL_SYNC_FINISHED, {
|
||||
successfully: false,
|
||||
errorMessage: "SyncError",
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
MessageSender,
|
||||
isExternalMessage,
|
||||
} from "@bitwarden/common/platform/messaging";
|
||||
import { SyncOptions } from "@bitwarden/common/platform/sync/sync.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
|
||||
import { DO_FULL_SYNC } from "./foreground-sync.service";
|
||||
@@ -34,15 +35,15 @@ export class SyncServiceListener {
|
||||
listener$(): Observable<void> {
|
||||
return this.messageListener.messages$(DO_FULL_SYNC).pipe(
|
||||
filter((message) => isExternalMessage(message)),
|
||||
concatMap(async ({ forceSync, allowThrowOnError, requestId }) => {
|
||||
await this.doFullSync(forceSync, allowThrowOnError, requestId);
|
||||
concatMap(async ({ forceSync, options, requestId }) => {
|
||||
await this.doFullSync(forceSync, options, requestId);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private async doFullSync(forceSync: boolean, allowThrowOnError: boolean, requestId: string) {
|
||||
private async doFullSync(forceSync: boolean, options: SyncOptions, requestId: string) {
|
||||
try {
|
||||
const result = await this.syncService.fullSync(forceSync, allowThrowOnError);
|
||||
const result = await this.syncService.fullSync(forceSync, options);
|
||||
this.messageSender.send(FULL_SYNC_FINISHED, {
|
||||
successfully: result,
|
||||
errorMessage: null,
|
||||
|
||||
Reference in New Issue
Block a user