Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/bitwarden/clients into vaul…
Browse files Browse the repository at this point in the history
…t/pm-9111/persist-add-edit
  • Loading branch information
nick-livefront committed Jan 14, 2025
2 parents b8b8c2c + 553d20f commit e8188f8
Show file tree
Hide file tree
Showing 27 changed files with 191 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,8 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
try {
const userKey = await this.biometricsService.unlockWithBiometricsForUser(userId);
result = await this.keyService.validateUserKey(userKey, userId);
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
result = false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { UserId } from "@bitwarden/common/types/guid";
import { UserKey } from "@bitwarden/common/types/key";
import { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
Expand Down Expand Up @@ -34,7 +35,7 @@ export class ForegroundBrowserBiometricsService extends BiometricsService {
if (!response.result) {
return null;
}
return response.result;
return SymmetricCryptoKey.fromString(response.result.keyB64) as UserKey;
}

async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
Expand Down
6 changes: 4 additions & 2 deletions apps/browser/src/popup/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
ToastOptions,
ToastService,
} from "@bitwarden/components";
import { BiometricStateService } from "@bitwarden/key-management";
import { BiometricsService, BiometricStateService } from "@bitwarden/key-management";

import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service";
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
Expand Down Expand Up @@ -66,6 +66,7 @@ export class AppComponent implements OnInit, OnDestroy {
private accountService: AccountService,
private animationControlService: AnimationControlService,
private biometricStateService: BiometricStateService,
private biometricsService: BiometricsService,
) {}

async ngOnInit() {
Expand Down Expand Up @@ -102,7 +103,7 @@ export class AppComponent implements OnInit, OnDestroy {

this.messageListener.allMessages$
.pipe(
tap((msg: any) => {
tap(async (msg: any) => {
if (msg.command === "doneLoggingOut") {
// TODO: PM-8544 - why do we call logout in the popup after receiving the doneLoggingOut message? Hasn't this already completeted logout?
this.authService.logOut(async () => {
Expand All @@ -119,6 +120,7 @@ export class AppComponent implements OnInit, OnDestroy {
msg.command === "locked" &&
(msg.userId == null || msg.userId == this.activeUserId)
) {
await this.biometricsService.setShouldAutopromptNow(false);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.router.navigate(["lock"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export class VaultPopupAutofillService {
[currentTabHostname as string]: { bannerIsDismissed: true },
});
}
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
throw new Error(
"There was a problem dismissing the blocked interaction URI notification banner",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@bitwarden/desktop",
"description": "A secure and free password manager for all of your devices.",
"version": "2025.1.1",
"version": "2025.1.2",
"keywords": [
"bitwarden",
"password",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/accounts/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
const skipSupportedPlatformCheck =
ipc.platform.allowBrowserintegrationOverride || ipc.platform.isDev;

if (skipSupportedPlatformCheck) {
if (!skipSupportedPlatformCheck) {
if (
ipc.platform.deviceType === DeviceType.MacOsDesktop &&
!this.platformUtilsService.isMacAppStore()
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/desktop/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@bitwarden/desktop",
"productName": "Bitwarden",
"description": "A secure and free password manager for all of your devices.",
"version": "2025.1.1",
"version": "2025.1.2",
"author": "Bitwarden Inc. <[email protected]> (https://bitwarden.com)",
"homepage": "https://bitwarden.com",
"license": "GPL-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export interface MemberDialogParams {
usesKeyConnector: boolean;
isOnSecretsManagerStandalone: boolean;
initialTab?: MemberDialogTab;
numConfirmedMembers: number;
numSeatsUsed: number;
managedByOrganization?: boolean;
}

Expand Down Expand Up @@ -263,7 +263,7 @@ export class MemberDialogComponent implements OnDestroy {
});

this.remainingSeats$ = this.organization$.pipe(
map((organization) => organization.seats - this.params.numConfirmedMembers),
map((organization) => organization.seats - this.params.numSeatsUsed),
);
}

Expand Down Expand Up @@ -458,7 +458,7 @@ export class MemberDialogComponent implements OnDestroy {
}
if (
organization.hasReseller &&
this.params.numConfirmedMembers + emails.length > organization.seats
this.params.numSeatsUsed + emails.length > organization.seats
) {
this.formGroup.controls.emails.setErrors({
tooManyEmails: { message: this.i18nService.t("seatLimitReachedContactYourProvider") },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,11 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
return;
}

const numSeatsUsed =
this.dataSource.confirmedUserCount +
this.dataSource.invitedUserCount +
this.dataSource.acceptedUserCount;

const dialog = openUserAddEditDialog(this.dialogService, {
data: {
name: this.userNamePipe.transform(user),
Expand All @@ -519,7 +524,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
usesKeyConnector: user?.usesKeyConnector,
isOnSecretsManagerStandalone: this.orgIsOnSecretsManagerStandalone,
initialTab: initialTab,
numConfirmedMembers: this.dataSource.confirmedUserCount,
numSeatsUsed,
managedByOrganization: user?.managedByOrganization,
},
});
Expand Down
33 changes: 33 additions & 0 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,39 @@
}
}
},
"atRiskApplicationsWithCount": {
"message": "At-risk applications ($COUNT$)",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
},
"atRiskMembersDescription": {
"message": "These members are logging into applications with weak, exposed, or reused passwords."
},
"atRiskApplicationsDescription": {
"message": "These applications have weak, exposed, or reused passwords."
},
"atRiskMembersDescriptionWithApp": {
"message": "These members are logging into $APPNAME$ with weak, exposed, or reused passwords.",
"placeholders": {
"appname": {
"content": "$1",
"example": "Salesforce"
}
}
},
"atRiskMembersWithCount": {
"message": "At-risk members ($COUNT$)",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
},
"atRiskMembersDescription": {
"message": "These members are logging into applications with weak, exposed, or reused passwords."
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,12 @@ export type AtRiskMemberDetail = {
email: string;
atRiskPasswordCount: number;
};

/*
* A list of applications and the count of
* at risk passwords for each application
*/
export type AtRiskApplicationDetail = {
applicationName: string;
atRiskPasswordCount: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ApplicationHealthReportDetail,
ApplicationHealthReportSummary,
AtRiskMemberDetail,
AtRiskApplicationDetail,
CipherHealthReportDetail,
CipherHealthReportUriDetail,
ExposedPasswordDetail,
Expand Down Expand Up @@ -114,6 +115,30 @@ export class RiskInsightsReportService {
}));
}

generateAtRiskApplicationList(
cipherHealthReportDetails: ApplicationHealthReportDetail[],
): AtRiskApplicationDetail[] {
const appsRiskMap = new Map<string, number>();

cipherHealthReportDetails
.filter((app) => app.atRiskPasswordCount > 0)
.forEach((app) => {
if (appsRiskMap.has(app.applicationName)) {
appsRiskMap.set(
app.applicationName,
appsRiskMap.get(app.applicationName) + app.atRiskPasswordCount,
);
} else {
appsRiskMap.set(app.applicationName, app.atRiskPasswordCount);
}
});

return Array.from(appsRiskMap.entries()).map(([applicationName, atRiskPasswordCount]) => ({
applicationName,
atRiskPasswordCount,
}));
}

/**
* Gets the summary from the application health report. Returns total members and applications as well
* as the total at risk members and at risk applications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ <h2 class="tw-mb-6" bitTypography="h2">{{ "allApplications" | i18n }}</h2>
>
</tools-card>
<tools-card
class="tw-flex-1"
class="tw-flex-1 tw-cursor-pointer"
[title]="'atRiskApplications' | i18n"
[value]="applicationSummary.totalAtRiskApplicationCount"
[maxValue]="applicationSummary.totalApplicationCount"
(click)="showOrgAtRiskApps()"
>
</tools-card>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";

import { openAppAtRiskMembersDialog } from "./app-at-risk-members-dialog.component";
import { OrgAtRiskAppsDialogComponent } from "./org-at-risk-apps-dialog.component";
import { OrgAtRiskMembersDialogComponent } from "./org-at-risk-members-dialog.component";
import { ApplicationsLoadingComponent } from "./risk-insights-loading.component";

Expand Down Expand Up @@ -154,6 +155,12 @@ export class AllApplicationsComponent implements OnInit, OnDestroy {
});
};

showOrgAtRiskApps = async () => {
this.dialogService.open(OrgAtRiskAppsDialogComponent, {
data: this.reportService.generateAtRiskApplicationList(this.dataSource.data),
});
};

onCheckboxChange(id: number, event: Event) {
const isChecked = (event.target as HTMLInputElement).checked;
if (isChecked) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<bit-dialog>
<ng-container bitDialogTitle>
<span bitDialogTitle>{{ "atRiskApplicationsWithCount" | i18n: atRiskApps.length }} </span>
</ng-container>
<ng-container bitDialogContent>
<div class="tw-flex tw-flex-col tw-gap-2">
<span bitTypography="body1">{{ "atRiskApplicationsDescription" | i18n }}</span>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div bitTypography="body2" class="tw-font-bold">{{ "application" | i18n }}</div>
<div bitTypography="body2" class="tw-font-bold">{{ "atRiskPasswords" | i18n }}</div>
</div>
<ng-container *ngFor="let app of atRiskApps">
<div class="tw-flex tw-justify-between tw-mt-2">
<div>{{ app.applicationName }}</div>
<div>{{ app.atRiskPasswordCount }}</div>
</div>
</ng-container>
</div>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton bitDialogClose buttonType="secondary" type="button">
{{ "close" | i18n }}
</button>
</ng-container>
</bit-dialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { CommonModule } from "@angular/common";
import { Component, Inject } from "@angular/core";

import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AtRiskApplicationDetail } from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health";
import { ButtonModule, DialogModule, DialogService, TypographyModule } from "@bitwarden/components";

export const openOrgAtRiskMembersDialog = (
dialogService: DialogService,
dialogConfig: AtRiskApplicationDetail[],
) =>
dialogService.open<boolean, AtRiskApplicationDetail[]>(OrgAtRiskAppsDialogComponent, {
data: dialogConfig,
});

@Component({
standalone: true,
templateUrl: "./org-at-risk-apps-dialog.component.html",
imports: [ButtonModule, CommonModule, DialogModule, JslibModule, TypographyModule],
})
export class OrgAtRiskAppsDialogComponent {
constructor(@Inject(DIALOG_DATA) protected atRiskApps: AtRiskApplicationDetail[]) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class MemberAccessReportComponent implements OnInit {
usesKeyConnector: user?.usesKeyConnector,
isOnSecretsManagerStandalone: this.orgIsOnSecretsManagerStandalone,
initialTab: MemberDialogTab.Role,
numConfirmedMembers: this.dataSource.data.length,
numSeatsUsed: this.dataSource.data.length,
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ export class LoginDecryptionOptionsComponent implements OnInit {
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
private validationService: ValidationService,
) {
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
this.clientType === this.platformUtilsService.getClientType();
this.clientType = this.platformUtilsService.getClientType();
}

async ngOnInit() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
let status = await firstValueFrom(authService.authStatusFor$(userId as UserId));
status = await authService.getAuthStatus(userId);
if (status === AuthenticationStatus.Unlocked) {
this.logService.info(
"[Process Reload Service] User unlocked, preventing process reload",
);
return;
}
}
Expand All @@ -55,6 +58,9 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
if (userId != null) {
const ephemeralPin = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
if (ephemeralPin != null) {
this.logService.info(
"[Process Reload Service] Ephemeral pin active, preventing process reload",
);
return;
}
}
Expand Down Expand Up @@ -97,7 +103,12 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
await this.reloadCallback();
}
return;
} else {
this.logService.info(
"[Process Reload Service] Desktop ipc fingerprint validated, preventing process reload",
);
}

if (this.reloadInterval == null) {
this.reloadInterval = setInterval(async () => await this.executeProcessReload(), 1000);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ export abstract class SendApiService {
postSend: (request: SendRequest) => Promise<SendResponse>;
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
putSendRemovePassword: (id: string) => Promise<SendResponse>;
deleteSend: (id: string) => Promise<any>;
Expand Down
Loading

0 comments on commit e8188f8

Please sign in to comment.