PM-7392 - TokenSvc - Replace messageSender with logout callback per PR feedback.
This commit is contained in:
parent
d88766a028
commit
bcf9099229
|
@ -1,3 +1,4 @@
|
||||||
|
import { LogoutReason } from "@bitwarden/auth/common";
|
||||||
import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||||
|
|
||||||
|
@ -22,10 +23,6 @@ import {
|
||||||
LogServiceInitOptions,
|
LogServiceInitOptions,
|
||||||
logServiceFactory,
|
logServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/log-service.factory";
|
} from "../../../platform/background/service-factories/log-service.factory";
|
||||||
import {
|
|
||||||
MessagingServiceInitOptions,
|
|
||||||
messagingServiceFactory,
|
|
||||||
} from "../../../platform/background/service-factories/messaging-service.factory";
|
|
||||||
import {
|
import {
|
||||||
PlatformUtilsServiceInitOptions,
|
PlatformUtilsServiceInitOptions,
|
||||||
platformUtilsServiceFactory,
|
platformUtilsServiceFactory,
|
||||||
|
@ -39,7 +36,11 @@ import {
|
||||||
secureStorageServiceFactory,
|
secureStorageServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/storage-service.factory";
|
} from "../../../platform/background/service-factories/storage-service.factory";
|
||||||
|
|
||||||
type TokenServiceFactoryOptions = FactoryOptions;
|
type TokenServiceFactoryOptions = FactoryOptions & {
|
||||||
|
tokenServiceOptions: {
|
||||||
|
logoutCallback: (logoutReason: LogoutReason, userId?: string) => Promise<void>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export type TokenServiceInitOptions = TokenServiceFactoryOptions &
|
export type TokenServiceInitOptions = TokenServiceFactoryOptions &
|
||||||
SingleUserStateProviderInitOptions &
|
SingleUserStateProviderInitOptions &
|
||||||
|
@ -48,8 +49,7 @@ export type TokenServiceInitOptions = TokenServiceFactoryOptions &
|
||||||
SecureStorageServiceInitOptions &
|
SecureStorageServiceInitOptions &
|
||||||
KeyGenerationServiceInitOptions &
|
KeyGenerationServiceInitOptions &
|
||||||
EncryptServiceInitOptions &
|
EncryptServiceInitOptions &
|
||||||
LogServiceInitOptions &
|
LogServiceInitOptions;
|
||||||
MessagingServiceInitOptions;
|
|
||||||
|
|
||||||
export function tokenServiceFactory(
|
export function tokenServiceFactory(
|
||||||
cache: { tokenService?: AbstractTokenService } & CachedServices,
|
cache: { tokenService?: AbstractTokenService } & CachedServices,
|
||||||
|
@ -68,7 +68,7 @@ export function tokenServiceFactory(
|
||||||
await keyGenerationServiceFactory(cache, opts),
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
await encryptServiceFactory(cache, opts),
|
await encryptServiceFactory(cache, opts),
|
||||||
await logServiceFactory(cache, opts),
|
await logServiceFactory(cache, opts),
|
||||||
await messagingServiceFactory(cache, opts),
|
opts.tokenServiceOptions.logoutCallback,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -520,7 +520,7 @@ export default class MainBackground {
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.messagingService,
|
logoutCallback,
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationRunner = new MigrationRunner(
|
const migrationRunner = new MigrationRunner(
|
||||||
|
|
|
@ -258,6 +258,9 @@ export class Main {
|
||||||
p = path.join(process.env.HOME, ".config/Bitwarden CLI");
|
p = path.join(process.env.HOME, ".config/Bitwarden CLI");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logoutCallback = async (logoutReason: LogoutReason, userId?: UserId) =>
|
||||||
|
await this.logout(logoutReason, userId);
|
||||||
|
|
||||||
this.platformUtilsService = new CliPlatformUtilsService(ClientType.Cli, packageJson);
|
this.platformUtilsService = new CliPlatformUtilsService(ClientType.Cli, packageJson);
|
||||||
this.logService = new ConsoleLogService(
|
this.logService = new ConsoleLogService(
|
||||||
this.platformUtilsService.isDev(),
|
this.platformUtilsService.isDev(),
|
||||||
|
@ -340,7 +343,7 @@ export class Main {
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.messagingService,
|
logoutCallback,
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationRunner = new MigrationRunner(
|
const migrationRunner = new MigrationRunner(
|
||||||
|
@ -397,7 +400,7 @@ export class Main {
|
||||||
throw new Error("Refresh Access token error");
|
throw new Error("Refresh Access token error");
|
||||||
},
|
},
|
||||||
this.logService,
|
this.logService,
|
||||||
async (logoutReason: LogoutReason) => await this.logout(),
|
logoutCallback,
|
||||||
customUserAgent,
|
customUserAgent,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -459,7 +462,7 @@ export class Main {
|
||||||
this.logService,
|
this.logService,
|
||||||
this.organizationService,
|
this.organizationService,
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
async (logoutReason: LogoutReason) => await this.logout(),
|
logoutCallback,
|
||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -652,7 +655,7 @@ export class Main {
|
||||||
this.sendApiService,
|
this.sendApiService,
|
||||||
this.userDecryptionOptionsService,
|
this.userDecryptionOptionsService,
|
||||||
this.avatarService,
|
this.avatarService,
|
||||||
async (logoutReason: LogoutReason) => await this.logout(),
|
logoutCallback,
|
||||||
this.billingAccountProfileStateService,
|
this.billingAccountProfileStateService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
);
|
);
|
||||||
|
@ -733,7 +736,7 @@ export class Main {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async logout() {
|
async logout(logoutReason: LogoutReason, passedInUserId?: UserId) {
|
||||||
this.authService.logOut(() => {
|
this.authService.logOut(() => {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as path from "path";
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { Subject, firstValueFrom } from "rxjs";
|
import { Subject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { LogoutReason } from "@bitwarden/auth/common";
|
||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||||
|
@ -203,7 +204,7 @@ export class Main {
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.messagingService,
|
async (logoutReason: LogoutReason) => {},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.migrationRunner = new MigrationRunner(
|
this.migrationRunner = new MigrationRunner(
|
||||||
|
|
|
@ -533,7 +533,7 @@ const safeProviders: SafeProvider[] = [
|
||||||
KeyGenerationServiceAbstraction,
|
KeyGenerationServiceAbstraction,
|
||||||
EncryptService,
|
EncryptService,
|
||||||
LogService,
|
LogService,
|
||||||
MessagingServiceAbstraction,
|
LOGOUT_CALLBACK,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { MockProxy, mock } from "jest-mock-extended";
|
import { MockProxy, mock } from "jest-mock-extended";
|
||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { LogoutReason } from "@bitwarden/auth/common";
|
||||||
|
|
||||||
import { FakeSingleUserStateProvider, FakeGlobalStateProvider } from "../../../spec";
|
import { FakeSingleUserStateProvider, FakeGlobalStateProvider } from "../../../spec";
|
||||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||||
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
||||||
import { LogService } from "../../platform/abstractions/log.service";
|
import { LogService } from "../../platform/abstractions/log.service";
|
||||||
import { MessagingService } from "../../platform/abstractions/messaging.service";
|
|
||||||
import { AbstractStorageService } from "../../platform/abstractions/storage.service";
|
import { AbstractStorageService } from "../../platform/abstractions/storage.service";
|
||||||
import { StorageLocation } from "../../platform/enums";
|
import { StorageLocation } from "../../platform/enums";
|
||||||
import { StorageOptions } from "../../platform/models/domain/storage-options";
|
import { StorageOptions } from "../../platform/models/domain/storage-options";
|
||||||
|
@ -38,7 +39,7 @@ describe("TokenService", () => {
|
||||||
let keyGenerationService: MockProxy<KeyGenerationService>;
|
let keyGenerationService: MockProxy<KeyGenerationService>;
|
||||||
let encryptService: MockProxy<EncryptService>;
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let messagingService: MockProxy<MessagingService>;
|
let logoutCallback: jest.Mock<Promise<void>, [logoutReason: LogoutReason, userId?: string]>;
|
||||||
|
|
||||||
const memoryVaultTimeoutAction = VaultTimeoutAction.LogOut;
|
const memoryVaultTimeoutAction = VaultTimeoutAction.LogOut;
|
||||||
const memoryVaultTimeout = 30;
|
const memoryVaultTimeout = 30;
|
||||||
|
@ -99,7 +100,7 @@ describe("TokenService", () => {
|
||||||
keyGenerationService = mock<KeyGenerationService>();
|
keyGenerationService = mock<KeyGenerationService>();
|
||||||
encryptService = mock<EncryptService>();
|
encryptService = mock<EncryptService>();
|
||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
messagingService = mock<MessagingService>();
|
logoutCallback = jest.fn();
|
||||||
|
|
||||||
const supportsSecureStorage = false; // default to false; tests will override as needed
|
const supportsSecureStorage = false; // default to false; tests will override as needed
|
||||||
tokenService = createTokenService(supportsSecureStorage);
|
tokenService = createTokenService(supportsSecureStorage);
|
||||||
|
@ -533,10 +534,10 @@ describe("TokenService", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert that we logged the user out
|
// assert that we logged the user out
|
||||||
expect(messagingService.send).toHaveBeenCalledWith("logout", {
|
expect(logoutCallback).toHaveBeenCalledWith(
|
||||||
userId: userIdFromAccessToken,
|
"accessTokenUnableToBeDecrypted",
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
userIdFromAccessToken,
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("logs the error and logs the user out when secure storage errors on trying to get an access token key", async () => {
|
it("logs the error and logs the user out when secure storage errors on trying to get an access token key", async () => {
|
||||||
|
@ -568,10 +569,10 @@ describe("TokenService", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert that we logged the user out
|
// assert that we logged the user out
|
||||||
expect(messagingService.send).toHaveBeenCalledWith("logout", {
|
expect(logoutCallback).toHaveBeenCalledWith(
|
||||||
userId: userIdFromAccessToken,
|
"accessTokenUnableToBeDecrypted",
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
userIdFromAccessToken,
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1366,7 +1367,7 @@ describe("TokenService", () => {
|
||||||
// assert that we did not log an error or log the user out
|
// assert that we did not log an error or log the user out
|
||||||
expect(logService.error).not.toHaveBeenCalled();
|
expect(logService.error).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(messagingService.send).not.toHaveBeenCalledWith("logout", expect.anything());
|
expect(logoutCallback).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not error and fallback to disk storage when passed a null value for the refresh token", async () => {
|
it("does not error and fallback to disk storage when passed a null value for the refresh token", async () => {
|
||||||
|
@ -1425,10 +1426,10 @@ describe("TokenService", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert that we logged the user out
|
// assert that we logged the user out
|
||||||
expect(messagingService.send).toHaveBeenCalledWith("logout", {
|
expect(logoutCallback).toHaveBeenCalledWith(
|
||||||
userId: userIdFromAccessToken,
|
"accessTokenUnableToBeDecrypted",
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
userIdFromAccessToken,
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1688,10 +1689,10 @@ describe("TokenService", () => {
|
||||||
new Error(secureStorageSvcMockErrorMsg),
|
new Error(secureStorageSvcMockErrorMsg),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(messagingService.send).toHaveBeenCalledWith("logout", {
|
expect(logoutCallback).toHaveBeenCalledWith(
|
||||||
userId: userIdFromAccessToken,
|
"refreshTokenSecureStorageRetrievalFailure",
|
||||||
reason: "refreshTokenSecureStorageRetrievalFailure",
|
userIdFromAccessToken,
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2651,7 +2652,7 @@ describe("TokenService", () => {
|
||||||
keyGenerationService,
|
keyGenerationService,
|
||||||
encryptService,
|
encryptService,
|
||||||
logService,
|
logService,
|
||||||
messagingService,
|
logoutCallback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Observable, combineLatest, firstValueFrom, map } from "rxjs";
|
import { Observable, combineLatest, firstValueFrom, map } from "rxjs";
|
||||||
import { Opaque } from "type-fest";
|
import { Opaque } from "type-fest";
|
||||||
|
|
||||||
import { decodeJwtTokenToJson } from "@bitwarden/auth/common";
|
import { LogoutReason, decodeJwtTokenToJson } from "@bitwarden/auth/common";
|
||||||
|
|
||||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||||
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
import { EncryptService } from "../../platform/abstractions/encrypt.service";
|
||||||
|
@ -9,7 +9,6 @@ import { KeyGenerationService } from "../../platform/abstractions/key-generation
|
||||||
import { LogService } from "../../platform/abstractions/log.service";
|
import { LogService } from "../../platform/abstractions/log.service";
|
||||||
import { AbstractStorageService } from "../../platform/abstractions/storage.service";
|
import { AbstractStorageService } from "../../platform/abstractions/storage.service";
|
||||||
import { StorageLocation } from "../../platform/enums";
|
import { StorageLocation } from "../../platform/enums";
|
||||||
import { MessageSender } from "../../platform/messaging";
|
|
||||||
import { EncString, EncryptedString } from "../../platform/models/domain/enc-string";
|
import { EncString, EncryptedString } from "../../platform/models/domain/enc-string";
|
||||||
import { StorageOptions } from "../../platform/models/domain/storage-options";
|
import { StorageOptions } from "../../platform/models/domain/storage-options";
|
||||||
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
@ -132,7 +131,7 @@ export class TokenService implements TokenServiceAbstraction {
|
||||||
private keyGenerationService: KeyGenerationService,
|
private keyGenerationService: KeyGenerationService,
|
||||||
private encryptService: EncryptService,
|
private encryptService: EncryptService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private messageSender: MessageSender,
|
private logoutCallback: (logoutReason: LogoutReason, userId?: string) => Promise<void>,
|
||||||
) {
|
) {
|
||||||
this.initializeState();
|
this.initializeState();
|
||||||
}
|
}
|
||||||
|
@ -410,10 +409,7 @@ export class TokenService implements TokenServiceAbstraction {
|
||||||
"Access token key retrieval failed. Unable to decrypt encrypted access token. Logging user out.",
|
"Access token key retrieval failed. Unable to decrypt encrypted access token. Logging user out.",
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
this.messageSender.send("logout", {
|
await this.logoutCallback("accessTokenUnableToBeDecrypted", userId);
|
||||||
userId,
|
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
|
||||||
});
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,10 +428,9 @@ export class TokenService implements TokenServiceAbstraction {
|
||||||
this.logService.error(
|
this.logService.error(
|
||||||
"Access token key not found to decrypt encrypted access token. Logging user out.",
|
"Access token key not found to decrypt encrypted access token. Logging user out.",
|
||||||
);
|
);
|
||||||
this.messageSender.send("logout", {
|
|
||||||
userId,
|
await this.logoutCallback("accessTokenUnableToBeDecrypted", userId);
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
|
||||||
});
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,10 +451,9 @@ export class TokenService implements TokenServiceAbstraction {
|
||||||
// We don't try to recover here since we'd like to know
|
// We don't try to recover here since we'd like to know
|
||||||
// if access token and key are getting out of sync.
|
// if access token and key are getting out of sync.
|
||||||
this.logService.error(`Failed to decrypt access token`, error);
|
this.logService.error(`Failed to decrypt access token`, error);
|
||||||
this.messageSender.send("logout", {
|
|
||||||
userId,
|
await this.logoutCallback("accessTokenUnableToBeDecrypted", userId);
|
||||||
reason: "accessTokenUnableToBeDecrypted",
|
|
||||||
});
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,13 +582,7 @@ export class TokenService implements TokenServiceAbstraction {
|
||||||
|
|
||||||
this.logService.error(`Failed to retrieve refresh token from secure storage`, error);
|
this.logService.error(`Failed to retrieve refresh token from secure storage`, error);
|
||||||
|
|
||||||
// This is not ideal as we would like to use the LOGOUT_CALLBACK injection token
|
await this.logoutCallback("refreshTokenSecureStorageRetrievalFailure", userId);
|
||||||
// instead of directly using the MessagingService here. However, we can't customize the
|
|
||||||
// logout reason if we do so.
|
|
||||||
this.messageSender.send("logout", {
|
|
||||||
userId,
|
|
||||||
reason: "refreshTokenSecureStorageRetrievalFailure",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue