mirror of
https://github.com/bitwarden/browser
synced 2026-02-13 06:54:07 +00:00
Merge branch 'main' into ps/extension-refresh
This commit is contained in:
@@ -11,7 +11,6 @@ import { DisableTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/mod
|
||||
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request";
|
||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
|
||||
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -127,13 +126,6 @@ export class TwoFactorAuthenticatorComponent
|
||||
}
|
||||
|
||||
protected override async disableMethod() {
|
||||
const twoFactorAuthenticatorTokenFeatureFlag = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.AuthenticatorTwoFactorToken,
|
||||
);
|
||||
if (twoFactorAuthenticatorTokenFeatureFlag === false) {
|
||||
return super.disableMethod();
|
||||
}
|
||||
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "disable" },
|
||||
content: { key: "twoStepDisableDesc" },
|
||||
|
||||
@@ -403,11 +403,13 @@ export class ChangePlanDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get upgradeRequiresPaymentMethod() {
|
||||
return (
|
||||
this.organization?.productTierType === ProductTierType.Free &&
|
||||
!this.showFree &&
|
||||
!this.billing?.paymentSource
|
||||
);
|
||||
const isFreeTier = this.organization?.productTierType === ProductTierType.Free;
|
||||
const shouldHideFree = !this.showFree;
|
||||
const hasNoPaymentSource = this.deprecateStripeSourcesAPI
|
||||
? !this.paymentSource
|
||||
: !this.billing?.paymentSource;
|
||||
|
||||
return isFreeTier && shouldHideFree && hasNoPaymentSource;
|
||||
}
|
||||
|
||||
get selectedSecretsManagerPlan() {
|
||||
|
||||
@@ -318,8 +318,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const allCiphers$ = organization$.pipe(
|
||||
concatMap(async (organization) => {
|
||||
const allCiphers$ = combineLatest([organization$, this.refresh$]).pipe(
|
||||
switchMap(async ([organization]) => {
|
||||
// If user swaps organization reset the addAccessToggle
|
||||
if (!this.showAddAccessToggle || organization) {
|
||||
this.addAccessToggle(0);
|
||||
@@ -343,6 +343,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
await this.searchService.indexCiphers(ciphers, organization.id);
|
||||
return ciphers;
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const allCipherMap$ = allCiphers$.pipe(
|
||||
|
||||
@@ -2,7 +2,6 @@ import { firstValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||
|
||||
import { FeatureFlag } from "../../enums/feature-flag.enum";
|
||||
import { AppIdService } from "../../platform/abstractions/app-id.service";
|
||||
import { ConfigService } from "../../platform/abstractions/config/config.service";
|
||||
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
|
||||
@@ -334,9 +333,6 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
||||
}
|
||||
|
||||
async recordDeviceTrustLoss(): Promise<void> {
|
||||
if (!(await this.configService.getFeatureFlag(FeatureFlag.DeviceTrustLogging))) {
|
||||
return;
|
||||
}
|
||||
const deviceIdentifier = await this.appIdService.getAppId();
|
||||
await this.devicesApiService.postDeviceTrustLoss(deviceIdentifier);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ export enum FeatureFlag {
|
||||
VaultBulkManagementAction = "vault-bulk-management-action",
|
||||
AC2828_ProviderPortalMembersPage = "AC-2828_provider-portal-members-page",
|
||||
IdpAutoSubmitLogin = "idp-auto-submit-login",
|
||||
DeviceTrustLogging = "pm-8285-device-trust-logging",
|
||||
AuthenticatorTwoFactorToken = "authenticator-2fa-token",
|
||||
UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh",
|
||||
EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub",
|
||||
GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor",
|
||||
@@ -69,8 +67,6 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.VaultBulkManagementAction]: FALSE,
|
||||
[FeatureFlag.AC2828_ProviderPortalMembersPage]: FALSE,
|
||||
[FeatureFlag.IdpAutoSubmitLogin]: FALSE,
|
||||
[FeatureFlag.DeviceTrustLogging]: FALSE,
|
||||
[FeatureFlag.AuthenticatorTwoFactorToken]: FALSE,
|
||||
[FeatureFlag.UnauthenticatedExtensionUIRefresh]: FALSE,
|
||||
[FeatureFlag.EnableUpgradePasswordManagerSub]: FALSE,
|
||||
[FeatureFlag.GenerateIdentityFillScriptRefactor]: FALSE,
|
||||
|
||||
@@ -15,12 +15,19 @@
|
||||
<bit-label *ngIf="!hasPassword">{{ "password" | i18n }}</bit-label>
|
||||
<bit-label *ngIf="hasPassword">{{ "newPassword" | i18n }}</bit-label>
|
||||
<input bitInput type="password" formControlName="password" />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
<button
|
||||
data-testid="toggle-visibility-for-password"
|
||||
type="button"
|
||||
bitIconButton
|
||||
bitSuffix
|
||||
bitPasswordInputToggle
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-generate"
|
||||
bitSuffix
|
||||
[appA11yTitle]="'generatePassword' | i18n"
|
||||
data-testid="generate-password"
|
||||
></button>
|
||||
<bit-hint>{{ "sendPasswordDescV2" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
@@ -97,6 +97,7 @@ export class SendOptionsComponent implements OnInit {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.sendFormContainer.originalSendView) {
|
||||
this.sendOptionsForm.patchValue({
|
||||
@@ -107,5 +108,8 @@ export class SendOptionsComponent implements OnInit {
|
||||
notes: this.sendFormContainer.originalSendView.notes,
|
||||
});
|
||||
}
|
||||
if (!this.config.areSendsAllowed) {
|
||||
this.sendOptionsForm.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
|
||||
import { SendFormConfig } from "../../abstractions/send-form-config.service";
|
||||
import { SendFormContainer } from "../../send-form-container";
|
||||
|
||||
// Value = hours
|
||||
export enum DatePreset {
|
||||
OneHour = 1,
|
||||
OneDay = 24,
|
||||
TwoDays = 48,
|
||||
ThreeDays = 72,
|
||||
SevenDays = 168,
|
||||
FourteenDays = 336,
|
||||
ThirtyDays = 720,
|
||||
}
|
||||
|
||||
export interface DatePresetSelectOption {
|
||||
name: string;
|
||||
value: DatePreset | string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "base-send-details-behavior",
|
||||
template: "",
|
||||
})
|
||||
export class BaseSendDetailsComponent implements OnInit {
|
||||
@Input() config: SendFormConfig;
|
||||
@Input() originalSendView?: SendView;
|
||||
|
||||
customDeletionDateOption: DatePresetSelectOption | null = null;
|
||||
datePresetOptions: DatePresetSelectOption[] = [];
|
||||
|
||||
sendDetailsForm = this.formBuilder.group({
|
||||
name: new FormControl("", Validators.required),
|
||||
selectedDeletionDatePreset: new FormControl(DatePreset.SevenDays || "", Validators.required),
|
||||
});
|
||||
|
||||
constructor(
|
||||
protected sendFormContainer: SendFormContainer,
|
||||
protected formBuilder: FormBuilder,
|
||||
protected i18nService: I18nService,
|
||||
protected datePipe: DatePipe,
|
||||
) {
|
||||
this.sendDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.sendFormContainer.patchSend((send) => {
|
||||
return Object.assign(send, {
|
||||
name: value.name,
|
||||
deletionDate: new Date(this.formattedDeletionDate),
|
||||
expirationDate: new Date(this.formattedDeletionDate),
|
||||
} as SendView);
|
||||
});
|
||||
});
|
||||
|
||||
this.sendFormContainer.registerChildForm("sendDetailsForm", this.sendDetailsForm);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.setupDeletionDatePresets();
|
||||
|
||||
if (this.originalSendView) {
|
||||
this.sendDetailsForm.patchValue({
|
||||
name: this.originalSendView.name,
|
||||
selectedDeletionDatePreset: this.originalSendView.deletionDate.toString(),
|
||||
});
|
||||
|
||||
if (this.originalSendView.deletionDate) {
|
||||
this.customDeletionDateOption = {
|
||||
name: this.datePipe.transform(this.originalSendView.deletionDate, "MM/dd/yyyy, hh:mm a"),
|
||||
value: this.originalSendView.deletionDate.toString(),
|
||||
};
|
||||
this.datePresetOptions.unshift(this.customDeletionDateOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupDeletionDatePresets() {
|
||||
const defaultSelections: DatePresetSelectOption[] = [
|
||||
{ name: this.i18nService.t("oneHour"), value: DatePreset.OneHour },
|
||||
{ name: this.i18nService.t("oneDay"), value: DatePreset.OneDay },
|
||||
{ name: this.i18nService.t("days", "2"), value: DatePreset.TwoDays },
|
||||
{ name: this.i18nService.t("days", "3"), value: DatePreset.ThreeDays },
|
||||
{ name: this.i18nService.t("days", "7"), value: DatePreset.SevenDays },
|
||||
{ name: this.i18nService.t("days", "14"), value: DatePreset.FourteenDays },
|
||||
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
||||
];
|
||||
|
||||
this.datePresetOptions = defaultSelections;
|
||||
}
|
||||
|
||||
get formattedDeletionDate(): string {
|
||||
const now = new Date();
|
||||
const selectedValue = this.sendDetailsForm.controls.selectedDeletionDatePreset.value;
|
||||
|
||||
if (typeof selectedValue === "string") {
|
||||
return selectedValue;
|
||||
}
|
||||
|
||||
const milliseconds = now.setTime(now.getTime() + (selectedValue as number) * 60 * 60 * 1000);
|
||||
return new Date(milliseconds).toString();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<bit-form-field *ngIf="sendLink">
|
||||
<bit-label>{{ "sendLink" | i18n }}</bit-label>
|
||||
<input bitInput type="text" [value]="sendLink" readonly />
|
||||
<input data-testid="send-link" bitInput type="text" [value]="sendLink" readonly />
|
||||
<button
|
||||
type="button"
|
||||
bitSuffix
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { CommonModule, DatePipe } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
import { Component, OnInit, Input } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import {
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
@@ -18,13 +20,29 @@ import {
|
||||
SelectModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { SendFormConfig } from "../../abstractions/send-form-config.service";
|
||||
import { SendFormContainer } from "../../send-form-container";
|
||||
import { SendOptionsComponent } from "../options/send-options.component";
|
||||
|
||||
import { BaseSendDetailsComponent } from "./base-send-details.component";
|
||||
import { SendFileDetailsComponent } from "./send-file-details.component";
|
||||
import { SendTextDetailsComponent } from "./send-text-details.component";
|
||||
|
||||
// Value = hours
|
||||
export enum DatePreset {
|
||||
OneHour = 1,
|
||||
OneDay = 24,
|
||||
TwoDays = 48,
|
||||
ThreeDays = 72,
|
||||
SevenDays = 168,
|
||||
FourteenDays = 336,
|
||||
ThirtyDays = 720,
|
||||
}
|
||||
|
||||
export interface DatePresetSelectOption {
|
||||
name: string;
|
||||
value: DatePreset | string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "tools-send-details",
|
||||
templateUrl: "./send-details.component.html",
|
||||
@@ -46,10 +64,20 @@ import { SendTextDetailsComponent } from "./send-text-details.component";
|
||||
SelectModule,
|
||||
],
|
||||
})
|
||||
export class SendDetailsComponent extends BaseSendDetailsComponent implements OnInit {
|
||||
export class SendDetailsComponent implements OnInit {
|
||||
@Input() config: SendFormConfig;
|
||||
@Input() originalSendView?: SendView;
|
||||
|
||||
FileSendType = SendType.File;
|
||||
TextSendType = SendType.Text;
|
||||
sendLink: string | null = null;
|
||||
customDeletionDateOption: DatePresetSelectOption | null = null;
|
||||
datePresetOptions: DatePresetSelectOption[] = [];
|
||||
|
||||
sendDetailsForm = this.formBuilder.group({
|
||||
name: new FormControl("", Validators.required),
|
||||
selectedDeletionDatePreset: new FormControl(DatePreset.SevenDays || "", Validators.required),
|
||||
});
|
||||
|
||||
constructor(
|
||||
protected sendFormContainer: SendFormContainer,
|
||||
@@ -58,18 +86,69 @@ export class SendDetailsComponent extends BaseSendDetailsComponent implements On
|
||||
protected datePipe: DatePipe,
|
||||
protected environmentService: EnvironmentService,
|
||||
) {
|
||||
super(sendFormContainer, formBuilder, i18nService, datePipe);
|
||||
}
|
||||
this.sendDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.sendFormContainer.patchSend((send) => {
|
||||
return Object.assign(send, {
|
||||
name: value.name,
|
||||
deletionDate: new Date(this.formattedDeletionDate),
|
||||
expirationDate: new Date(this.formattedDeletionDate),
|
||||
} as SendView);
|
||||
});
|
||||
});
|
||||
|
||||
async getSendLink() {}
|
||||
this.sendFormContainer.registerChildForm("sendDetailsForm", this.sendDetailsForm);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await super.ngOnInit();
|
||||
if (!this.originalSendView) {
|
||||
return;
|
||||
this.setupDeletionDatePresets();
|
||||
|
||||
if (this.originalSendView) {
|
||||
this.sendDetailsForm.patchValue({
|
||||
name: this.originalSendView.name,
|
||||
selectedDeletionDatePreset: this.originalSendView.deletionDate.toString(),
|
||||
});
|
||||
|
||||
if (this.originalSendView.deletionDate) {
|
||||
this.customDeletionDateOption = {
|
||||
name: this.datePipe.transform(this.originalSendView.deletionDate, "short"),
|
||||
value: this.originalSendView.deletionDate.toString(),
|
||||
};
|
||||
this.datePresetOptions.unshift(this.customDeletionDateOption);
|
||||
}
|
||||
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
this.sendLink =
|
||||
env.getSendUrl() + this.originalSendView.accessId + "/" + this.originalSendView.urlB64Key;
|
||||
}
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
this.sendLink =
|
||||
env.getSendUrl() + this.originalSendView.accessId + "/" + this.originalSendView.urlB64Key;
|
||||
|
||||
if (!this.config.areSendsAllowed) {
|
||||
this.sendDetailsForm.disable();
|
||||
}
|
||||
}
|
||||
|
||||
setupDeletionDatePresets() {
|
||||
const defaultSelections: DatePresetSelectOption[] = [
|
||||
{ name: this.i18nService.t("oneHour"), value: DatePreset.OneHour },
|
||||
{ name: this.i18nService.t("oneDay"), value: DatePreset.OneDay },
|
||||
{ name: this.i18nService.t("days", "2"), value: DatePreset.TwoDays },
|
||||
{ name: this.i18nService.t("days", "3"), value: DatePreset.ThreeDays },
|
||||
{ name: this.i18nService.t("days", "7"), value: DatePreset.SevenDays },
|
||||
{ name: this.i18nService.t("days", "14"), value: DatePreset.FourteenDays },
|
||||
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
||||
];
|
||||
|
||||
this.datePresetOptions = defaultSelections;
|
||||
}
|
||||
|
||||
get formattedDeletionDate(): string {
|
||||
const now = new Date();
|
||||
const selectedValue = this.sendDetailsForm.controls.selectedDeletionDatePreset.value;
|
||||
|
||||
if (typeof selectedValue === "string") {
|
||||
return selectedValue;
|
||||
}
|
||||
|
||||
const milliseconds = now.setTime(now.getTime() + (selectedValue as number) * 60 * 60 * 1000);
|
||||
return new Date(milliseconds).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<bit-section [formGroup]="sendFileDetailsForm">
|
||||
<div *ngIf="config.mode === 'edit'">
|
||||
<div bitTypography="body2" class="tw-text-muted">{{ "file" | i18n }}</div>
|
||||
<div>{{ originalSendView.file.fileName }}</div>
|
||||
<div class="tw-text-muted">{{ originalSendView.file.sizeName }}</div>
|
||||
<div data-testid="file-name">{{ originalSendView.file.fileName }}</div>
|
||||
<div data-testid="file-size" class="tw-text-muted">{{ originalSendView.file.sizeName }}</div>
|
||||
</div>
|
||||
<bit-form-field *ngIf="config.mode !== 'edit'">
|
||||
<bit-label for="file">{{ "fileToShare" | i18n }}</bit-label>
|
||||
|
||||
@@ -73,5 +73,9 @@ export class SendFileDetailsComponent implements OnInit {
|
||||
file: this.originalSendView.file,
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.config.areSendsAllowed) {
|
||||
this.sendFileDetailsForm.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,5 +57,9 @@ export class SendTextDetailsComponent implements OnInit {
|
||||
hidden: this.originalSendView.text?.hidden || false,
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.config.areSendsAllowed) {
|
||||
this.sendTextDetailsForm.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -164,7 +164,7 @@
|
||||
"prettier": "3.3.3",
|
||||
"prettier-plugin-tailwindcss": "0.6.6",
|
||||
"process": "0.11.10",
|
||||
"regedit": "^3.0.3",
|
||||
"regedit": "3.0.3",
|
||||
"remark-gfm": "4.0.0",
|
||||
"rimraf": "6.0.1",
|
||||
"sass": "1.74.1",
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
"prettier": "3.3.3",
|
||||
"prettier-plugin-tailwindcss": "0.6.6",
|
||||
"process": "0.11.10",
|
||||
"regedit": "^3.0.3",
|
||||
"regedit": "3.0.3",
|
||||
"remark-gfm": "4.0.0",
|
||||
"rimraf": "6.0.1",
|
||||
"sass": "1.74.1",
|
||||
|
||||
Reference in New Issue
Block a user