1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00
Files
browser/libs/common/spec/fake-account-service.ts
Jeffrey Holland b62220ace1 Autofill/pm 17444 use reprompt (#14004)
* 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>
2025-04-11 09:41:30 +02:00

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,
};