mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
[PM-14423] item view security task (#13485)
* show pending change password tasks for ciphers in extension
This commit is contained in:
@@ -5163,5 +5163,8 @@
|
|||||||
},
|
},
|
||||||
"updateDesktopAppOrDisableFingerprintDialogMessage": {
|
"updateDesktopAppOrDisableFingerprintDialogMessage": {
|
||||||
"message": "To use biometric unlock, please update your desktop application, or disable fingerprint unlock in the desktop settings."
|
"message": "To use biometric unlock, please update your desktop application, or disable fingerprint unlock in the desktop settings."
|
||||||
|
},
|
||||||
|
"changeAtRiskPassword": {
|
||||||
|
"message": "Change at-risk password"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,16 @@ import {
|
|||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
ToastService,
|
ToastService,
|
||||||
|
CalloutModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { CipherViewComponent, CopyCipherFieldService } from "@bitwarden/vault";
|
import {
|
||||||
|
ChangeLoginPasswordService,
|
||||||
|
CipherViewComponent,
|
||||||
|
CopyCipherFieldService,
|
||||||
|
DefaultChangeLoginPasswordService,
|
||||||
|
DefaultTaskService,
|
||||||
|
TaskService,
|
||||||
|
} from "@bitwarden/vault";
|
||||||
|
|
||||||
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
||||||
@@ -82,10 +90,13 @@ type LoadAction =
|
|||||||
CipherViewComponent,
|
CipherViewComponent,
|
||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
PopOutComponent,
|
PopOutComponent,
|
||||||
|
CalloutModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ViewPasswordHistoryService, useClass: BrowserViewPasswordHistoryService },
|
{ provide: ViewPasswordHistoryService, useClass: BrowserViewPasswordHistoryService },
|
||||||
{ provide: PremiumUpgradePromptService, useClass: BrowserPremiumUpgradePromptService },
|
{ provide: PremiumUpgradePromptService, useClass: BrowserPremiumUpgradePromptService },
|
||||||
|
{ provide: TaskService, useClass: DefaultTaskService },
|
||||||
|
{ provide: ChangeLoginPasswordService, useClass: DefaultChangeLoginPasswordService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ViewV2Component {
|
export class ViewV2Component {
|
||||||
|
|||||||
@@ -3604,5 +3604,8 @@
|
|||||||
},
|
},
|
||||||
"updateBrowserOrDisableFingerprintDialogMessage": {
|
"updateBrowserOrDisableFingerprintDialogMessage": {
|
||||||
"message": "The browser extension you are using is out of date. Please update it or disable browser integration fingerprint validation in the desktop app settings."
|
"message": "The browser extension you are using is out of date. Please update it or disable browser integration fingerprint validation in the desktop app settings."
|
||||||
|
},
|
||||||
|
"changeAtRiskPassword": {
|
||||||
|
"message": "Change at-risk password"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import { mock } from "jest-mock-extended";
|
|||||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
@@ -15,6 +17,7 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde
|
|||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
import { ChangeLoginPasswordService, TaskService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { EmergencyViewDialogComponent } from "./emergency-view-dialog.component";
|
import { EmergencyViewDialogComponent } from "./emergency-view-dialog.component";
|
||||||
|
|
||||||
@@ -52,7 +55,34 @@ describe("EmergencyViewDialogComponent", () => {
|
|||||||
{ provide: DIALOG_DATA, useValue: { cipher: mockCipher } },
|
{ provide: DIALOG_DATA, useValue: { cipher: mockCipher } },
|
||||||
{ provide: AccountService, useValue: accountService },
|
{ provide: AccountService, useValue: accountService },
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
})
|
||||||
|
.overrideComponent(EmergencyViewDialogComponent, {
|
||||||
|
remove: {
|
||||||
|
providers: [
|
||||||
|
{ provide: PlatformUtilsService, useValue: PlatformUtilsService },
|
||||||
|
{
|
||||||
|
provide: ChangeLoginPasswordService,
|
||||||
|
useValue: ChangeLoginPasswordService,
|
||||||
|
},
|
||||||
|
{ provide: ConfigService, useValue: ConfigService },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
add: {
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: TaskService,
|
||||||
|
useValue: mock<TaskService>(),
|
||||||
|
},
|
||||||
|
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||||
|
{
|
||||||
|
provide: ChangeLoginPasswordService,
|
||||||
|
useValue: mock<ChangeLoginPasswordService>(),
|
||||||
|
},
|
||||||
|
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(EmergencyViewDialogComponent);
|
fixture = TestBed.createComponent(EmergencyViewDialogComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions
|
|||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
|
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
|
||||||
import { CipherViewComponent } from "@bitwarden/vault";
|
import { CipherViewComponent, DefaultTaskService, TaskService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { WebViewPasswordHistoryService } from "../../../../vault/services/web-view-password-history.service";
|
import { WebViewPasswordHistoryService } from "../../../../vault/services/web-view-password-history.service";
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ class PremiumUpgradePromptNoop implements PremiumUpgradePromptService {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
||||||
{ provide: PremiumUpgradePromptService, useClass: PremiumUpgradePromptNoop },
|
{ provide: PremiumUpgradePromptService, useClass: PremiumUpgradePromptNoop },
|
||||||
|
{ provide: TaskService, useClass: DefaultTaskService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class EmergencyViewDialogComponent {
|
export class EmergencyViewDialogComponent {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
ToastService,
|
ToastService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import {
|
import {
|
||||||
|
ChangeLoginPasswordService,
|
||||||
CipherAttachmentsComponent,
|
CipherAttachmentsComponent,
|
||||||
CipherFormComponent,
|
CipherFormComponent,
|
||||||
CipherFormConfig,
|
CipherFormConfig,
|
||||||
@@ -43,6 +44,9 @@ import {
|
|||||||
CipherFormModule,
|
CipherFormModule,
|
||||||
CipherViewComponent,
|
CipherViewComponent,
|
||||||
DecryptionFailureDialogComponent,
|
DecryptionFailureDialogComponent,
|
||||||
|
DefaultChangeLoginPasswordService,
|
||||||
|
DefaultTaskService,
|
||||||
|
TaskService,
|
||||||
} from "@bitwarden/vault";
|
} from "@bitwarden/vault";
|
||||||
|
|
||||||
import { SharedModule } from "../../../shared/shared.module";
|
import { SharedModule } from "../../../shared/shared.module";
|
||||||
@@ -136,6 +140,8 @@ export enum VaultItemDialogResult {
|
|||||||
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
||||||
{ provide: CipherFormGenerationService, useClass: WebCipherFormGenerationService },
|
{ provide: CipherFormGenerationService, useClass: WebCipherFormGenerationService },
|
||||||
RoutedVaultFilterService,
|
RoutedVaultFilterService,
|
||||||
|
{ provide: TaskService, useClass: DefaultTaskService },
|
||||||
|
{ provide: ChangeLoginPasswordService, useClass: DefaultChangeLoginPasswordService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
@@ -21,6 +22,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|||||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
import { DialogService, ToastService } from "@bitwarden/components";
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
import { KeyService } from "@bitwarden/key-management";
|
||||||
|
import { ChangeLoginPasswordService, DefaultTaskService, TaskService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { ViewCipherDialogParams, ViewCipherDialogResult, ViewComponent } from "./view.component";
|
import { ViewCipherDialogParams, ViewCipherDialogResult, ViewComponent } from "./view.component";
|
||||||
|
|
||||||
@@ -82,7 +84,33 @@ describe("ViewComponent", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
})
|
||||||
|
.overrideComponent(ViewComponent, {
|
||||||
|
remove: {
|
||||||
|
providers: [
|
||||||
|
{ provide: TaskService, useClass: DefaultTaskService },
|
||||||
|
{ provide: PlatformUtilsService, useValue: PlatformUtilsService },
|
||||||
|
{
|
||||||
|
provide: ChangeLoginPasswordService,
|
||||||
|
useValue: ChangeLoginPasswordService,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
add: {
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: TaskService,
|
||||||
|
useValue: mock<TaskService>(),
|
||||||
|
},
|
||||||
|
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||||
|
{
|
||||||
|
provide: ChangeLoginPasswordService,
|
||||||
|
useValue: mock<ChangeLoginPasswordService>(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ViewComponent);
|
fixture = TestBed.createComponent(ViewComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
DialogService,
|
DialogService,
|
||||||
ToastService,
|
ToastService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { CipherViewComponent } from "@bitwarden/vault";
|
import { CipherViewComponent, DefaultTaskService, TaskService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { SharedModule } from "../../shared/shared.module";
|
import { SharedModule } from "../../shared/shared.module";
|
||||||
import { WebVaultPremiumUpgradePromptService } from "../services/web-premium-upgrade-prompt.service";
|
import { WebVaultPremiumUpgradePromptService } from "../services/web-premium-upgrade-prompt.service";
|
||||||
@@ -74,6 +74,7 @@ export interface ViewCipherDialogCloseResult {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
{ provide: ViewPasswordHistoryService, useClass: WebViewPasswordHistoryService },
|
||||||
{ provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService },
|
{ provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService },
|
||||||
|
{ provide: TaskService, useClass: DefaultTaskService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ViewComponent implements OnInit {
|
export class ViewComponent implements OnInit {
|
||||||
|
|||||||
@@ -10503,6 +10503,9 @@
|
|||||||
"assignedExceedsAvailable": {
|
"assignedExceedsAvailable": {
|
||||||
"message": "Assigned seats exceed available seats."
|
"message": "Assigned seats exceed available seats."
|
||||||
},
|
},
|
||||||
|
"changeAtRiskPassword": {
|
||||||
|
"message": "Change at-risk password"
|
||||||
|
},
|
||||||
"removeUnlockWithPinPolicyTitle": {
|
"removeUnlockWithPinPolicyTitle": {
|
||||||
"message": "Remove Unlock with PIN"
|
"message": "Remove Unlock with PIN"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,19 @@
|
|||||||
{{ "cardExpiredMessage" | i18n }}
|
{{ "cardExpiredMessage" | i18n }}
|
||||||
</bit-callout>
|
</bit-callout>
|
||||||
|
|
||||||
|
<ng-container *ngIf="isSecurityTasksEnabled$ | async">
|
||||||
|
<bit-callout
|
||||||
|
*ngIf="cipher?.login.uris.length > 0 && hadPendingChangePasswordTask"
|
||||||
|
type="warning"
|
||||||
|
[title]="''"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-exclamation-triangle tw-text-warning" aria-hidden="true"></i>
|
||||||
|
<a bitLink (click)="launchChangePassword()">
|
||||||
|
{{ "changeAtRiskPassword" | i18n }}
|
||||||
|
<i class="bwi bwi-popout tw-ml-1" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</bit-callout>
|
||||||
|
</ng-container>
|
||||||
<!-- HELPER TEXT -->
|
<!-- HELPER TEXT -->
|
||||||
<p
|
<p
|
||||||
class="tw-text-sm tw-text-muted"
|
class="tw-text-sm tw-text-muted"
|
||||||
@@ -23,7 +36,15 @@
|
|||||||
</app-item-details-v2>
|
</app-item-details-v2>
|
||||||
|
|
||||||
<!-- LOGIN CREDENTIALS -->
|
<!-- LOGIN CREDENTIALS -->
|
||||||
<app-login-credentials-view *ngIf="hasLogin" [cipher]="cipher"></app-login-credentials-view>
|
<app-login-credentials-view
|
||||||
|
*ngIf="hasLogin"
|
||||||
|
[cipher]="cipher"
|
||||||
|
[activeUserId]="activeUserId$ | async"
|
||||||
|
[hadPendingChangePasswordTask]="
|
||||||
|
hadPendingChangePasswordTask && (isSecurityTasksEnabled$ | async)
|
||||||
|
"
|
||||||
|
(handleChangePassword)="launchChangePassword()"
|
||||||
|
></app-login-credentials-view>
|
||||||
|
|
||||||
<!-- AUTOFILL OPTIONS -->
|
<!-- AUTOFILL OPTIONS -->
|
||||||
<app-autofill-options-view
|
<app-autofill-options-view
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, Input, OnChanges, OnDestroy } from "@angular/core";
|
import { Component, Input, OnChanges, OnDestroy } from "@angular/core";
|
||||||
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
@@ -12,11 +12,17 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { isCardExpired } from "@bitwarden/common/autofill/utils";
|
import { isCardExpired } from "@bitwarden/common/autofill/utils";
|
||||||
import { CollectionId } from "@bitwarden/common/types/guid";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
|
||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||||
import { CalloutModule, SearchModule } from "@bitwarden/components";
|
import { AnchorLinkDirective, CalloutModule, SearchModule } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { ChangeLoginPasswordService } from "../abstractions/change-login-password.service";
|
||||||
|
import { TaskService, SecurityTaskType } from "../tasks";
|
||||||
|
|
||||||
import { AdditionalOptionsComponent } from "./additional-options/additional-options.component";
|
import { AdditionalOptionsComponent } from "./additional-options/additional-options.component";
|
||||||
import { AttachmentsV2ViewComponent } from "./attachments/attachments-v2-view.component";
|
import { AttachmentsV2ViewComponent } from "./attachments/attachments-v2-view.component";
|
||||||
@@ -48,12 +54,13 @@ import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-ide
|
|||||||
ViewIdentitySectionsComponent,
|
ViewIdentitySectionsComponent,
|
||||||
LoginCredentialsViewComponent,
|
LoginCredentialsViewComponent,
|
||||||
AutofillOptionsViewComponent,
|
AutofillOptionsViewComponent,
|
||||||
|
AnchorLinkDirective,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CipherViewComponent implements OnChanges, OnDestroy {
|
export class CipherViewComponent implements OnChanges, OnDestroy {
|
||||||
@Input({ required: true }) cipher: CipherView | null = null;
|
@Input({ required: true }) cipher: CipherView | null = null;
|
||||||
|
|
||||||
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
|
activeUserId$ = getUserId(this.accountService.activeAccount$);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional list of collections the cipher is assigned to. If none are provided, they will be fetched using the
|
* Optional list of collections the cipher is assigned to. If none are provided, they will be fetched using the
|
||||||
@@ -68,12 +75,18 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
|
|||||||
folder$: Observable<FolderView | undefined> | undefined;
|
folder$: Observable<FolderView | undefined> | undefined;
|
||||||
private destroyed$: Subject<void> = new Subject();
|
private destroyed$: Subject<void> = new Subject();
|
||||||
cardIsExpired: boolean = false;
|
cardIsExpired: boolean = false;
|
||||||
|
hadPendingChangePasswordTask: boolean = false;
|
||||||
|
isSecurityTasksEnabled$ = this.configService.getFeatureFlag$(FeatureFlag.SecurityTasks);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
|
private defaultTaskService: TaskService,
|
||||||
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private changeLoginPasswordService: ChangeLoginPasswordService,
|
||||||
|
private configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnChanges() {
|
async ngOnChanges() {
|
||||||
@@ -137,7 +150,11 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
const userId = await firstValueFrom(this.activeUserId$);
|
||||||
|
|
||||||
|
if (this.cipher.edit && this.cipher.viewPassword) {
|
||||||
|
await this.checkPendingChangePasswordTasks(userId);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.cipher.organizationId && userId) {
|
if (this.cipher.organizationId && userId) {
|
||||||
this.organization$ = this.organizationService
|
this.organization$ = this.organizationService
|
||||||
@@ -147,15 +164,29 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.cipher.folderId) {
|
if (this.cipher.folderId) {
|
||||||
const activeUserId = await firstValueFrom(this.activeUserId$);
|
|
||||||
|
|
||||||
if (!activeUserId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.folder$ = this.folderService
|
this.folder$ = this.folderService
|
||||||
.getDecrypted$(this.cipher.folderId, activeUserId)
|
.getDecrypted$(this.cipher.folderId, userId)
|
||||||
.pipe(takeUntil(this.destroyed$));
|
.pipe(takeUntil(this.destroyed$));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkPendingChangePasswordTasks(userId: UserId): Promise<void> {
|
||||||
|
const tasks = await firstValueFrom(this.defaultTaskService.pendingTasks$(userId));
|
||||||
|
|
||||||
|
this.hadPendingChangePasswordTask = tasks?.some((task) => {
|
||||||
|
return (
|
||||||
|
task.cipherId === this.cipher?.id && task.type === SecurityTaskType.UpdateAtRiskCredential
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
launchChangePassword = async () => {
|
||||||
|
if (this.cipher != null) {
|
||||||
|
const url = await this.changeLoginPasswordService.getChangePasswordUrl(this.cipher);
|
||||||
|
if (url == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.platformUtilsService.launchUri(url);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,12 @@
|
|||||||
(click)="logCopyEvent()"
|
(click)="logCopyEvent()"
|
||||||
></button>
|
></button>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
|
<bit-hint *ngIf="hadPendingChangePasswordTask">
|
||||||
|
<a bitLink (click)="launchChangePasswordEvent()">
|
||||||
|
{{ "changeAtRiskPassword" | i18n }}
|
||||||
|
<i class="bwi bwi-popout tw-ml-1" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</bit-hint>
|
||||||
<div
|
<div
|
||||||
*ngIf="showPasswordCount && passwordRevealed"
|
*ngIf="showPasswordCount && passwordRevealed"
|
||||||
[ngClass]="{ 'tw-mt-3': !cipher.login.totp, 'tw-mb-2': true }"
|
[ngClass]="{ 'tw-mt-3': !cipher.login.totp, 'tw-mb-2': true }"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
@@ -74,6 +75,7 @@ describe("LoginCredentialsViewComponent", () => {
|
|||||||
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||||
{ provide: I18nService, useValue: { t: (...keys: string[]) => keys.join(" ") } },
|
{ provide: I18nService, useValue: { t: (...keys: string[]) => keys.join(" ") } },
|
||||||
|
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { CommonModule, DatePipe } from "@angular/common";
|
import { CommonModule, DatePipe } from "@angular/common";
|
||||||
import { Component, inject, Input } from "@angular/core";
|
import { Component, EventEmitter, inject, Input, Output } from "@angular/core";
|
||||||
import { Observable, switchMap } from "rxjs";
|
import { Observable, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
@@ -10,6 +10,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
|||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import {
|
import {
|
||||||
@@ -17,6 +18,7 @@ import {
|
|||||||
SectionComponent,
|
SectionComponent,
|
||||||
SectionHeaderComponent,
|
SectionHeaderComponent,
|
||||||
TypographyModule,
|
TypographyModule,
|
||||||
|
LinkModule,
|
||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
BadgeModule,
|
BadgeModule,
|
||||||
ColorPasswordModule,
|
ColorPasswordModule,
|
||||||
@@ -46,10 +48,14 @@ type TotpCodeValues = {
|
|||||||
ColorPasswordModule,
|
ColorPasswordModule,
|
||||||
BitTotpCountdownComponent,
|
BitTotpCountdownComponent,
|
||||||
ReadOnlyCipherCardComponent,
|
ReadOnlyCipherCardComponent,
|
||||||
|
LinkModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class LoginCredentialsViewComponent {
|
export class LoginCredentialsViewComponent {
|
||||||
@Input() cipher: CipherView;
|
@Input() cipher: CipherView;
|
||||||
|
@Input() activeUserId: UserId;
|
||||||
|
@Input() hadPendingChangePasswordTask: boolean;
|
||||||
|
@Output() handleChangePassword = new EventEmitter<void>();
|
||||||
|
|
||||||
isPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
isPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
||||||
switchMap((account) =>
|
switchMap((account) =>
|
||||||
@@ -59,6 +65,7 @@ export class LoginCredentialsViewComponent {
|
|||||||
showPasswordCount: boolean = false;
|
showPasswordCount: boolean = false;
|
||||||
passwordRevealed: boolean = false;
|
passwordRevealed: boolean = false;
|
||||||
totpCodeCopyObj: TotpCodeValues;
|
totpCodeCopyObj: TotpCodeValues;
|
||||||
|
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -111,4 +118,8 @@ export class LoginCredentialsViewComponent {
|
|||||||
this.cipher.organizationId,
|
this.cipher.organizationId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
launchChangePasswordEvent(): void {
|
||||||
|
this.handleChangePassword.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class DefaultChangeLoginPasswordService implements ChangeLoginPasswordSer
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (!reliable || wellKnownChangeUrl == null) {
|
if (!reliable || wellKnownChangeUrl == null) {
|
||||||
return cipher.login.uri;
|
return url.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wellKnownChangeUrl;
|
return wellKnownChangeUrl;
|
||||||
|
|||||||
Reference in New Issue
Block a user