mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 14:23:32 +00:00
* Passkey stuff Co-authored-by: Anders Åberg <github@andersaberg.com> * Ugly hacks * Work On Modal State Management * Applying modalStyles * modal * Improved hide/show * fixed promise * File name * fix prettier * Protecting against null API's and undefined data * Only show fake popup to devs * cleanup mock code * rename minmimal-app to modal-app * Added comment * Added comment * removed old comment * Avoided changing minimum size * Add small comment * Rename component * adress feedback * Fixed uppercase file * Fixed build * Added codeowners * added void * commentary * feat: reset setting on app start * Moved reset to be in main / process launch * Add comment to create window * Added a little bit of styling * Use Messaging service to loadUrl * Enable passkeysautofill * Add logging * halfbaked * Integration working * And now it works without extra delay * Clean up * add note about messaging * lb * removed console.logs * Cleanup and adress review feedback * This hides the swift UI * add modal components * update modal with correct ciphers and functionality * add create screen * pick credential, draft * Remove logger * a whole lot of wiring * not working * Improved wiring * Cancel after 90s * Introduced observable * update cipher handling * update to use matchesUri * Launching bitwarden if its not running * Passing position from native to electron * Rename inModalMode to modalMode * remove tap * revert spaces * added back isDev * cleaned up a bit * Cleanup swift file * tweaked logging * clean up * Update apps/desktop/macos/autofill-extension/CredentialProviderViewController.swift Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Update apps/desktop/src/platform/main/autofill/native-autofill.main.ts Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Update apps/desktop/src/platform/services/desktop-settings.service.ts Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * adress position feedback * Update apps/desktop/macos/autofill-extension/CredentialProviderViewController.swift Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Removed extra logging * Adjusted error logging * Use .error to log errors * remove dead code * Update desktop-autofill.service.ts * use parseCredentialId instead of guidToRawFormat * Update apps/desktop/src/autofill/services/desktop-autofill.service.ts Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Change windowXy to a Record instead of [number,number] * Update apps/desktop/src/autofill/services/desktop-fido2-user-interface.service.ts Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Remove unsued dep and comment * changed timeout to be spec recommended maxium, 10 minutes, for now. * Correctly assume UP * Removed extra cancelRequest in deinint * Add timeout and UV to confirmChoseCipher UV is performed by UI, not the service * Improved docs regarding undefined cipherId * cleanup: UP is no longer undefined * Run completeError if ipc messages conversion failed * don't throw, instead return undefined * Disabled passkey provider * Throw error if no activeUserId was found * removed comment * Fixed lint * removed unsued service * reset entitlement formatting * Update entitlements.mas.plist * Fix build issues * Fix import issues * Update route names to use `fido2` * Fix being unable to select a passkey * Fix linting issues * Added support for handling a locked vault * Followup to fix merge issues and other comments * Update `userHandle` value * Add error handling for missing session or other errors * Remove unused route * Fix linting issues * Simplify updateCredential method * Add master password reprompt on passkey create * Followup to remove comments and timeouts and handle errors * Address lint issue by using `takeUntilDestroyed` * Add MP prompt to cipher selection * Change how timeout is handled * Include `of` from rxjs * Hide blue header for passkey popouts (#14095) * Hide blue header for passkey popouts * Fix issue with test * Fix ngOnDestroy complaint * Import OnDestroy correctly * Only require master password if item requires it --------- Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com> Co-authored-by: Anders Åberg <github@andersaberg.com> Co-authored-by: Anders Åberg <anders@andersaberg.com> Co-authored-by: Colton Hurst <colton@coltonhurst.com> Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com> Co-authored-by: Evan Bassler <evanbassler@Mac.attlocal.net> Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>
131 lines
4.8 KiB
TypeScript
131 lines
4.8 KiB
TypeScript
// FIXME: Update this file to be type safe and remove this and next line
|
|
// @ts-strict-ignore
|
|
import { mock } from "jest-mock-extended";
|
|
import { ReplaySubject, combineLatest, map, Observable } from "rxjs";
|
|
|
|
import { Account, AccountInfo, AccountService } from "../src/auth/abstractions/account.service";
|
|
import { UserId } from "../src/types/guid";
|
|
|
|
export function mockAccountServiceWith(
|
|
userId: UserId,
|
|
info: Partial<AccountInfo> = {},
|
|
activity: Record<UserId, Date> = {},
|
|
): FakeAccountService {
|
|
const fullInfo: AccountInfo = {
|
|
...info,
|
|
...{
|
|
name: "name",
|
|
email: "email",
|
|
emailVerified: true,
|
|
},
|
|
};
|
|
|
|
const fullActivity = { [userId]: new Date(), ...activity };
|
|
|
|
const service = new FakeAccountService({ [userId]: fullInfo }, fullActivity);
|
|
service.activeAccountSubject.next({ id: userId, ...fullInfo });
|
|
return service;
|
|
}
|
|
|
|
export class FakeAccountService implements AccountService {
|
|
mock = mock<AccountService>();
|
|
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
accountsSubject = new ReplaySubject<Record<UserId, AccountInfo>>(1);
|
|
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
activeAccountSubject = new ReplaySubject<Account | null>(1);
|
|
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
accountActivitySubject = new ReplaySubject<Record<UserId, Date>>(1);
|
|
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
accountVerifyDevicesSubject = new ReplaySubject<boolean>(1);
|
|
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
showHeaderSubject = new ReplaySubject<boolean>(1);
|
|
private _activeUserId: UserId;
|
|
get activeUserId() {
|
|
return this._activeUserId;
|
|
}
|
|
accounts$ = this.accountsSubject.asObservable();
|
|
activeAccount$ = this.activeAccountSubject.asObservable();
|
|
accountActivity$ = this.accountActivitySubject.asObservable();
|
|
accountVerifyNewDeviceLogin$ = this.accountVerifyDevicesSubject.asObservable();
|
|
get sortedUserIds$() {
|
|
return this.accountActivity$.pipe(
|
|
map((activity) => {
|
|
return Object.entries(activity)
|
|
.map(([userId, lastActive]: [UserId, Date]) => ({ userId, lastActive }))
|
|
.sort((a, b) => a.lastActive.getTime() - b.lastActive.getTime())
|
|
.map((a) => a.userId);
|
|
}),
|
|
);
|
|
}
|
|
showHeader$ = this.showHeaderSubject.asObservable();
|
|
get nextUpAccount$(): Observable<Account> {
|
|
return combineLatest([this.accounts$, this.activeAccount$, this.sortedUserIds$]).pipe(
|
|
map(([accounts, activeAccount, sortedUserIds]) => {
|
|
const nextId = sortedUserIds.find((id) => id !== activeAccount?.id && accounts[id] != null);
|
|
return nextId ? { id: nextId, ...accounts[nextId] } : null;
|
|
}),
|
|
);
|
|
}
|
|
|
|
constructor(initialData: Record<UserId, AccountInfo>, accountActivity?: Record<UserId, Date>) {
|
|
this.accountsSubject.next(initialData);
|
|
this.activeAccountSubject.subscribe((data) => (this._activeUserId = data?.id));
|
|
this.activeAccountSubject.next(null);
|
|
this.accountActivitySubject.next(accountActivity);
|
|
}
|
|
|
|
setAccountVerifyNewDeviceLogin(userId: UserId, verifyNewDeviceLogin: boolean): Promise<void> {
|
|
return this.mock.setAccountVerifyNewDeviceLogin(userId, verifyNewDeviceLogin);
|
|
}
|
|
|
|
setAccountActivity(userId: UserId, lastActivity: Date): Promise<void> {
|
|
this.accountActivitySubject.next({
|
|
...this.accountActivitySubject["_buffer"][0],
|
|
[userId]: lastActivity,
|
|
});
|
|
return this.mock.setAccountActivity(userId, lastActivity);
|
|
}
|
|
|
|
async addAccount(userId: UserId, accountData: AccountInfo): Promise<void> {
|
|
const current = this.accountsSubject["_buffer"][0] ?? {};
|
|
this.accountsSubject.next({ ...current, [userId]: accountData });
|
|
await this.mock.addAccount(userId, accountData);
|
|
}
|
|
|
|
async setAccountName(userId: UserId, name: string): Promise<void> {
|
|
await this.mock.setAccountName(userId, name);
|
|
}
|
|
|
|
async setAccountEmail(userId: UserId, email: string): Promise<void> {
|
|
await this.mock.setAccountEmail(userId, email);
|
|
}
|
|
|
|
async setAccountEmailVerified(userId: UserId, emailVerified: boolean): Promise<void> {
|
|
await this.mock.setAccountEmailVerified(userId, emailVerified);
|
|
}
|
|
|
|
async switchAccount(userId: UserId): Promise<void> {
|
|
const next =
|
|
userId == null ? null : { id: userId, ...this.accountsSubject["_buffer"]?.[0]?.[userId] };
|
|
this.activeAccountSubject.next(next);
|
|
await this.mock.switchAccount(userId);
|
|
}
|
|
|
|
async clean(userId: UserId): Promise<void> {
|
|
const current = this.accountsSubject["_buffer"][0] ?? {};
|
|
const updated = { ...current, [userId]: loggedOutInfo };
|
|
this.accountsSubject.next(updated);
|
|
await this.mock.clean(userId);
|
|
}
|
|
|
|
async setShowHeader(value: boolean): Promise<void> {
|
|
this.showHeaderSubject.next(value);
|
|
}
|
|
}
|
|
|
|
const loggedOutInfo: AccountInfo = {
|
|
name: undefined,
|
|
email: "",
|
|
emailVerified: false,
|
|
};
|