1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-08 12:40:26 +00:00

Merge branch 'main' into auth/pm-18576/fix-missing-userid-on-remove-password

This commit is contained in:
Maciej Zieniuk
2025-03-10 17:51:36 +00:00
721 changed files with 38263 additions and 14874 deletions

View File

@@ -107,7 +107,6 @@ export class LoginViaAuthRequestComponentV1
this.authRequestService.authRequestPushNotification$
.pipe(takeUntil(this.destroy$))
.subscribe((id) => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.verifyAndHandleApprovedAuthReq(id).catch((e: Error) => {
this.toastService.showToast({
variant: "error",

View File

@@ -4,7 +4,6 @@ import { ActivatedRoute, convertToParamMap, Router } from "@angular/router";
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
// eslint-disable-next-line no-restricted-imports
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import {
LoginStrategyServiceAbstraction,

View File

@@ -6,7 +6,6 @@ import { ActivatedRoute, NavigationExtras, Router } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { first } from "rxjs/operators";
// eslint-disable-next-line no-restricted-imports
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import {
LoginStrategyServiceAbstraction,

View File

@@ -23,7 +23,6 @@ import { KeyService } from "@bitwarden/key-management";
@Directive({
selector: "app-user-verification",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class UserVerificationComponent implements ControlValueAccessor, OnInit, OnDestroy {
private _invalidSecret = false;
@Input()

View File

@@ -5,7 +5,6 @@ import { MockProxy, mock } from "jest-mock-extended";
import { BehaviorSubject, of } from "rxjs";
import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import {
Account,
AccountInfo,
@@ -16,6 +15,7 @@ import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractio
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { ClientType } from "@bitwarden/common/enums";
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { UserId } from "@bitwarden/common/types/guid";

View File

@@ -7,13 +7,13 @@ import {
} from "@angular/router";
import { firstValueFrom } from "rxjs";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { ClientType } from "@bitwarden/common/enums";
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { KeyService } from "@bitwarden/key-management";

View File

@@ -1,10 +1,10 @@
<ng-container *ngIf="loading">
<i
class="bwi bwi-spinner bwi-spin text-muted"
class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="sr-only">{{ "loading" | i18n }}</span>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</ng-container>
<bit-table *ngIf="!loading">
<ng-container header>

View File

@@ -59,8 +59,6 @@ export class AngularThemingService implements AbstractThemingService {
document.documentElement.classList.remove(
"theme_" + ThemeTypes.Light,
"theme_" + ThemeTypes.Dark,
"theme_" + ThemeTypes.Nord,
"theme_" + ThemeTypes.SolarizedDark,
);
document.documentElement.classList.add("theme_" + theme);
});

View File

@@ -4,6 +4,7 @@ import { Observable, Subject } from "rxjs";
import { LogoutReason } from "@bitwarden/auth/common";
import { ClientType } from "@bitwarden/common/enums";
import { VaultTimeout } from "@bitwarden/common/key-management/vault-timeout";
import { RegionConfig } from "@bitwarden/common/platform/abstractions/environment.service";
import {
AbstractStorageService,
@@ -12,7 +13,6 @@ import {
import { Theme } from "@bitwarden/common/platform/enums";
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
import { Message } from "@bitwarden/common/platform/messaging";
import { VaultTimeout } from "@bitwarden/common/types/vault-timeout.type";
import { SafeInjectionToken } from "@bitwarden/ui-common";
// Re-export the SafeInjectionToken from ui-common
export { SafeInjectionToken } from "@bitwarden/ui-common";

View File

@@ -45,8 +45,6 @@ import {
DefaultAuthRequestApiService,
DefaultLoginSuccessHandlerService,
LoginSuccessHandlerService,
PasswordLoginStrategy,
PasswordLoginStrategyData,
LoginApprovalComponentServiceAbstraction,
} from "@bitwarden/auth/common";
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
@@ -54,8 +52,6 @@ import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstr
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import {
InternalOrganizationServiceAbstraction,
@@ -157,6 +153,12 @@ import { BulkEncryptService } from "@bitwarden/common/key-management/crypto/abst
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { BulkEncryptServiceImplementation } from "@bitwarden/common/key-management/crypto/services/bulk-encrypt.service.implementation";
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/key-management/crypto/services/multithread-encrypt.service.implementation";
import {
DefaultVaultTimeoutService,
DefaultVaultTimeoutSettingsService,
VaultTimeoutService,
VaultTimeoutSettingsService,
} from "@bitwarden/common/key-management/vault-timeout";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
@@ -243,8 +245,6 @@ import { AuditService } from "@bitwarden/common/services/audit.service";
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { SearchService } from "@bitwarden/common/services/search.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service";
import {
PasswordStrengthService,
PasswordStrengthServiceAbstraction,
@@ -408,7 +408,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: ThemeStateService,
useClass: DefaultThemeStateService,
deps: [GlobalStateProvider, ConfigService],
deps: [GlobalStateProvider],
}),
safeProvider({
provide: AbstractThemingService,
@@ -463,7 +463,7 @@ const safeProviders: SafeProvider[] = [
InternalUserDecryptionOptionsServiceAbstraction,
GlobalStateProvider,
BillingAccountProfileStateService,
VaultTimeoutSettingsServiceAbstraction,
VaultTimeoutSettingsService,
KdfConfigService,
TaskSchedulerService,
],
@@ -603,7 +603,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: TotpServiceAbstraction,
useClass: TotpService,
deps: [CryptoFunctionServiceAbstraction, LogService],
deps: [SdkService],
}),
safeProvider({
provide: TokenServiceAbstraction,
@@ -697,7 +697,7 @@ const safeProviders: SafeProvider[] = [
REFRESH_ACCESS_TOKEN_ERROR_CALLBACK,
LogService,
LOGOUT_CALLBACK,
VaultTimeoutSettingsServiceAbstraction,
VaultTimeoutSettingsService,
],
}),
safeProvider({
@@ -762,8 +762,8 @@ const safeProviders: SafeProvider[] = [
deps: [MessageListener],
}),
safeProvider({
provide: VaultTimeoutSettingsServiceAbstraction,
useClass: VaultTimeoutSettingsService,
provide: VaultTimeoutSettingsService,
useClass: DefaultVaultTimeoutSettingsService,
deps: [
AccountServiceAbstraction,
PinServiceAbstraction,
@@ -778,8 +778,8 @@ const safeProviders: SafeProvider[] = [
],
}),
safeProvider({
provide: VaultTimeoutService,
useClass: VaultTimeoutService,
provide: DefaultVaultTimeoutService,
useClass: DefaultVaultTimeoutService,
deps: [
AccountServiceAbstraction,
InternalMasterPasswordServiceAbstraction,
@@ -791,7 +791,7 @@ const safeProviders: SafeProvider[] = [
SearchServiceAbstraction,
StateServiceAbstraction,
AuthServiceAbstraction,
VaultTimeoutSettingsServiceAbstraction,
VaultTimeoutSettingsService,
StateEventRunnerService,
TaskSchedulerService,
LogService,
@@ -801,8 +801,8 @@ const safeProviders: SafeProvider[] = [
],
}),
safeProvider({
provide: VaultTimeoutServiceAbstraction,
useExisting: VaultTimeoutService,
provide: VaultTimeoutService,
useExisting: DefaultVaultTimeoutService,
}),
safeProvider({
provide: SsoLoginServiceAbstraction,
@@ -1458,37 +1458,6 @@ const safeProviders: SafeProvider[] = [
useClass: DefaultLoginSuccessHandlerService,
deps: [SyncService, UserAsymmetricKeysRegenerationService],
}),
safeProvider({
provide: PasswordLoginStrategy,
useClass: PasswordLoginStrategy,
deps: [
PasswordLoginStrategyData,
PasswordStrengthServiceAbstraction,
PolicyServiceAbstraction,
LoginStrategyServiceAbstraction,
AccountServiceAbstraction,
InternalMasterPasswordServiceAbstraction,
KeyService,
EncryptService,
ApiServiceAbstraction,
TokenServiceAbstraction,
AppIdServiceAbstraction,
PlatformUtilsServiceAbstraction,
MessagingServiceAbstraction,
LogService,
StateServiceAbstraction,
TwoFactorServiceAbstraction,
InternalUserDecryptionOptionsServiceAbstraction,
BillingAccountProfileStateService,
VaultTimeoutSettingsServiceAbstraction,
KdfConfigService,
],
}),
safeProvider({
provide: PasswordLoginStrategyData,
useClass: PasswordLoginStrategyData,
deps: [],
}),
safeProvider({
provide: TaskService,
useClass: DefaultTaskService,

View File

@@ -14,6 +14,8 @@ import {
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -79,9 +81,12 @@ export class SendComponent implements OnInit, OnDestroy {
protected sendApiService: SendApiService,
protected dialogService: DialogService,
protected toastService: ToastService,
private accountService: AccountService,
) {}
async ngOnInit() {
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
this.policyService
.policyAppliesToActiveUser$(PolicyType.DisableSend)
.pipe(takeUntil(this.destroy$))
@@ -91,7 +96,7 @@ export class SendComponent implements OnInit, OnDestroy {
this._searchText$
.pipe(
switchMap((searchText) => from(this.searchService.isSearchable(searchText))),
switchMap((searchText) => from(this.searchService.isSearchable(userId, searchText))),
takeUntil(this.destroy$),
)
.subscribe((isSearchable) => {

View File

@@ -1,8 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { BehaviorSubject, Subject, firstValueFrom, from, map, switchMap, takeUntil } from "rxjs";
import { BehaviorSubject, Subject, firstValueFrom, from, switchMap, takeUntil } from "rxjs";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
@@ -22,14 +21,13 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
loaded = false;
ciphers: CipherView[] = [];
searchPlaceholder: string = null;
filter: (cipher: CipherView) => boolean = null;
deleted = false;
organization: Organization;
accessEvents = false;
protected searchPending = false;
private userId: UserId;
private destroy$ = new Subject<void>();
private searchTimeout: any = null;
private isSearchable: boolean = false;
@@ -45,25 +43,14 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
protected searchService: SearchService,
protected cipherService: CipherService,
protected accountService: AccountService,
) {
this.accountService.activeAccount$
.pipe(
getUserId,
switchMap((userId) =>
this.cipherService.cipherViews$(userId).pipe(map((ciphers) => ({ userId, ciphers }))),
),
takeUntilDestroyed(),
)
.subscribe(({ userId, ciphers }) => {
void this.doSearch(ciphers, userId);
this.loaded = true;
});
}
) {}
async ngOnInit() {
this.userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
ngOnInit(): void {
this._searchText$
.pipe(
switchMap((searchText) => from(this.searchService.isSearchable(searchText))),
switchMap((searchText) => from(this.searchService.isSearchable(this.userId, searchText))),
takeUntil(this.destroy$),
)
.subscribe((isSearchable) => {
@@ -149,6 +136,7 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
}
this.ciphers = await this.searchService.searchCiphers(
this.userId,
this.searchText,
[this.filter, this.deletedFilter],
indexedCiphers,

View File

@@ -41,6 +41,7 @@ import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.v
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
import { TotpInfo } from "@bitwarden/common/vault/services/totp.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { KeyService } from "@bitwarden/key-management";
import { PasswordRepromptService } from "@bitwarden/vault";
@@ -66,20 +67,19 @@ export class ViewComponent implements OnDestroy, OnInit {
showPrivateKey: boolean;
canAccessPremium: boolean;
showPremiumRequiredTotp: boolean;
totpCode: string;
totpCodeFormatted: string;
totpDash: number;
totpSec: number;
totpLow: boolean;
fieldType = FieldType;
checkPasswordPromise: Promise<number>;
folder: FolderView;
cipherType = CipherType;
private totpInterval: any;
private previousCipherId: string;
private passwordReprompted = false;
/**
* Represents TOTP information including display formatting and timing
*/
protected totpInfo$: Observable<TotpInfo> | undefined;
get fido2CredentialCreationDateValue(): string {
const dateCreated = this.i18nService.t("dateCreated");
const creationDate = this.datePipe.transform(
@@ -166,19 +166,33 @@ export class ViewComponent implements OnDestroy, OnInit {
).find((f) => f.id == this.cipher.folderId);
}
if (
const canGenerateTotp =
this.cipher.type === CipherType.Login &&
this.cipher.login.totp &&
(this.cipher.organizationUseTotp || this.canAccessPremium)
) {
await this.totpUpdateCode();
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
await this.totpTick(interval);
(this.cipher.organizationUseTotp || this.canAccessPremium);
this.totpInterval = setInterval(async () => {
await this.totpTick(interval);
}, 1000);
}
this.totpInfo$ = canGenerateTotp
? this.totpService.getCode$(this.cipher.login.totp).pipe(
map((response) => {
const epoch = Math.round(new Date().getTime() / 1000.0);
const mod = epoch % response.period;
// Format code
const totpCodeFormatted =
response.code.length > 4
? `${response.code.slice(0, Math.floor(response.code.length / 2))} ${response.code.slice(Math.floor(response.code.length / 2))}`
: response.code;
return {
totpCode: response.code,
totpCodeFormatted,
totpDash: +(Math.round(((78.6 / response.period) * mod + "e+2") as any) + "e-2"),
totpSec: response.period - mod,
totpLow: response.period - mod <= 7,
} as TotpInfo;
}),
)
: undefined;
if (this.previousCipherId !== this.cipherId) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
@@ -515,56 +529,11 @@ export class ViewComponent implements OnDestroy, OnInit {
}
private cleanUp() {
this.totpCode = null;
this.cipher = null;
this.folder = null;
this.showPassword = false;
this.showCardNumber = false;
this.showCardCode = false;
this.passwordReprompted = false;
if (this.totpInterval) {
clearInterval(this.totpInterval);
}
}
private async totpUpdateCode() {
if (
this.cipher == null ||
this.cipher.type !== CipherType.Login ||
this.cipher.login.totp == null
) {
if (this.totpInterval) {
clearInterval(this.totpInterval);
}
return;
}
this.totpCode = await this.totpService.getCode(this.cipher.login.totp);
if (this.totpCode != null) {
if (this.totpCode.length > 4) {
const half = Math.floor(this.totpCode.length / 2);
this.totpCodeFormatted =
this.totpCode.substring(0, half) + " " + this.totpCode.substring(half);
} else {
this.totpCodeFormatted = this.totpCode;
}
} else {
this.totpCodeFormatted = null;
if (this.totpInterval) {
clearInterval(this.totpInterval);
}
}
}
private async totpTick(intervalSeconds: number) {
const epoch = Math.round(new Date().getTime() / 1000.0);
const mod = epoch % intervalSeconds;
this.totpSec = intervalSeconds - mod;
this.totpDash = +(Math.round(((78.6 / intervalSeconds) * mod + "e+2") as any) + "e-2");
this.totpLow = this.totpSec <= 7;
if (mod === 0) {
await this.totpUpdateCode();
}
}
}

View File

@@ -1,7 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Injectable } from "@angular/core";
import { firstValueFrom, from, map, mergeMap, Observable, switchMap } from "rxjs";
import { firstValueFrom, from, map, mergeMap, Observable, switchMap, take } from "rxjs";
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@@ -85,6 +85,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
};
return this.accountService.activeAccount$.pipe(
take(1),
getUserId,
switchMap((userId) =>
this.folderService