1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-27 01:53:23 +00:00

Merge branch 'main' into feature/passkey-provider

This commit is contained in:
Jeffrey Holland
2025-10-10 16:42:39 +02:00
committed by GitHub
449 changed files with 15860 additions and 3942 deletions

View File

@@ -17,13 +17,13 @@ const CanLaunchWhitelist = [
];
export class SafeUrls {
static canLaunch(uri: string): boolean {
static canLaunch(uri: string | null | undefined): boolean {
if (Utils.isNullOrWhitespace(uri)) {
return false;
}
for (let i = 0; i < CanLaunchWhitelist.length; i++) {
if (uri.indexOf(CanLaunchWhitelist[i]) === 0) {
if (uri!.indexOf(CanLaunchWhitelist[i]) === 0) {
return true;
}
}

View File

@@ -375,7 +375,7 @@ export class Utils {
}
}
static getDomain(uriString: string): string {
static getDomain(uriString: string | null | undefined): string {
if (Utils.isNullOrWhitespace(uriString)) {
return null;
}
@@ -457,7 +457,7 @@ export class Utils {
return str == null || typeof str !== "string" || str.trim() === "";
}
static isNullOrEmpty(str: string | null): boolean {
static isNullOrEmpty(str: string | null | undefined): boolean {
return str == null || typeof str !== "string" || str == "";
}
@@ -479,7 +479,7 @@ export class Utils {
return (Object.keys(obj).filter((k) => Number.isNaN(+k)) as K[]).map((k) => obj[k]);
}
static getUrl(uriString: string): URL {
static getUrl(uriString: string | undefined | null): URL {
if (this.isNullOrWhitespace(uriString)) {
return null;
}

View File

@@ -27,8 +27,8 @@ export async function getCredentialsForAutofill(
cipherId: cipher.id,
credentialId: credId,
rpId: credential.rpId,
userHandle: credential.userHandle,
userName: credential.userName,
};
userHandle: credential.userHandle!,
userName: credential.userName!,
} satisfies Fido2CredentialAutofillView;
});
}

View File

@@ -8,11 +8,12 @@ import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-ma
import { BitwardenClient } from "@bitwarden/sdk-internal";
import {
ObservableTracker,
FakeAccountService,
FakeStateProvider,
mockAccountServiceWith,
ObservableTracker,
} from "../../../../spec";
import { ApiService } from "../../../abstractions/api.service";
import { AccountInfo } from "../../../auth/abstractions/account.service";
import { EncryptedString } from "../../../key-management/crypto/models/enc-string";
import { UserId } from "../../../types/guid";
@@ -46,6 +47,7 @@ describe("DefaultSdkService", () => {
let service!: DefaultSdkService;
let accountService!: FakeAccountService;
let fakeStateProvider!: FakeStateProvider;
let apiService!: MockProxy<ApiService>;
beforeEach(async () => {
await new TestSdkLoadService().loadAndInit();
@@ -55,6 +57,7 @@ describe("DefaultSdkService", () => {
platformUtilsService = mock<PlatformUtilsService>();
kdfConfigService = mock<KdfConfigService>();
keyService = mock<KeyService>();
apiService = mock<ApiService>();
const mockUserId = Utils.newGuid() as UserId;
accountService = mockAccountServiceWith(mockUserId);
fakeStateProvider = new FakeStateProvider(accountService);
@@ -72,6 +75,7 @@ describe("DefaultSdkService", () => {
accountService,
kdfConfigService,
keyService,
apiService,
fakeStateProvider,
configService,
);

View File

@@ -27,6 +27,7 @@ import {
UnsignedSharedKey,
} from "@bitwarden/sdk-internal";
import { ApiService } from "../../../abstractions/api.service";
import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service";
import { DeviceType } from "../../../enums/device-type.enum";
import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string";
@@ -43,7 +44,7 @@ import { StateProvider } from "../../state";
import { initializeState } from "./client-managed-state";
// A symbol that represents an overriden client that is explicitly set to undefined,
// A symbol that represents an overridden client that is explicitly set to undefined,
// blocking the creation of an internal client for that user.
const UnsetClient = Symbol("UnsetClient");
@@ -51,10 +52,17 @@ const UnsetClient = Symbol("UnsetClient");
* A token provider that exposes the access token to the SDK.
*/
class JsTokenProvider implements TokenProvider {
constructor() {}
constructor(
private apiService: ApiService,
private userId?: UserId,
) {}
async get_access_token(): Promise<string | undefined> {
return undefined;
if (this.userId == null) {
return undefined;
}
return await this.apiService.getActiveBearerToken(this.userId);
}
}
@@ -68,7 +76,10 @@ export class DefaultSdkService implements SdkService {
concatMap(async (env) => {
await SdkLoadService.Ready;
const settings = this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(new JsTokenProvider(), settings);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(this.apiService),
settings,
);
await this.loadFeatureFlags(client);
return client;
}),
@@ -87,6 +98,7 @@ export class DefaultSdkService implements SdkService {
private accountService: AccountService,
private kdfConfigService: KdfConfigService,
private keyService: KeyService,
private apiService: ApiService,
private stateProvider: StateProvider,
private configService: ConfigService,
private userAgent: string | null = null,
@@ -173,7 +185,7 @@ export class DefaultSdkService implements SdkService {
const settings = this.toSettings(env);
const client = await this.sdkClientFactory.createSdkClient(
new JsTokenProvider(),
new JsTokenProvider(this.apiService, userId),
settings,
);

View File

@@ -329,10 +329,8 @@ describe("DefaultSyncService", () => {
// Mock the value of this observable because it's used in `syncProfile`. Without it, the test breaks.
keyConnectorService.convertAccountRequired$ = of(false);
// Baseline date/time to compare sync time to, in order to avoid needing to use some kind of fake date provider.
const beforeSync = Date.now();
jest.useFakeTimers({ now: Date.now() });
// send it!
await sut.fullSync(true, defaultSyncOptions);
expectUpdateCallCount(mockUserState, 1);
@@ -340,9 +338,10 @@ describe("DefaultSyncService", () => {
const updateCall = mockUserState.update.mock.calls[0];
// Get the first argument to update(...) -- this will be the date callback that returns the date of the last successful sync
const dateCallback = updateCall[0];
const actualTime = dateCallback() as Date;
const actualDate = dateCallback() as Date;
expect(Math.abs(actualTime.getTime() - beforeSync)).toBeLessThan(1);
expect(actualDate.getTime()).toEqual(jest.now());
jest.useRealTimers();
});
it("updates last sync time when no sync is necessary", async () => {