mirror of
https://github.com/bitwarden/browser
synced 2026-02-12 22:44:11 +00:00
Merge branch 'main' into ps/extension-refresh
This commit is contained in:
@@ -2877,6 +2877,20 @@
|
||||
"generateEmail": {
|
||||
"message": "Generate email"
|
||||
},
|
||||
"generatorBoundariesHint": {
|
||||
"message": "Value must be between $MIN$ and $MAX$",
|
||||
"description": "Explains spin box minimum and maximum values to the user",
|
||||
"placeholders": {
|
||||
"min": {
|
||||
"content": "$1",
|
||||
"example": "8"
|
||||
},
|
||||
"max": {
|
||||
"content": "$2",
|
||||
"example": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"usernameType": {
|
||||
"message": "Username type"
|
||||
},
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"papaparse": "5.4.1",
|
||||
"proper-lockfile": "4.1.2",
|
||||
"rxjs": "7.8.1",
|
||||
"tldts": "6.1.52",
|
||||
"tldts": "6.1.56",
|
||||
"zxcvbn": "4.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
4
apps/desktop/desktop_native/Cargo.lock
generated
4
apps/desktop/desktop_native/Cargo.lock
generated
@@ -1965,9 +1965,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.11"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
||||
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
||||
@@ -40,7 +40,7 @@ scopeguard = "=1.2.0"
|
||||
sha2 = "=0.10.8"
|
||||
thiserror = "=1.0.61"
|
||||
tokio = { version = "=1.38.0", features = ["io-util", "sync", "macros"] }
|
||||
tokio-util = "=0.7.11"
|
||||
tokio-util = "=0.7.12"
|
||||
typenum = "=1.17.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
"module-alias": "2.2.3",
|
||||
"node-ipc": "9.2.1",
|
||||
"ts-node": "10.9.2",
|
||||
"uuid": "10.0.0",
|
||||
"uuid": "11.0.1",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.16.11",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
@@ -106,9 +106,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz",
|
||||
"integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==",
|
||||
"version": "20.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz",
|
||||
"integrity": "sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
@@ -421,16 +421,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.1.tgz",
|
||||
"integrity": "sha512-wt9UB5EcLhnboy1UvA1mvGPXkIIrHSu+3FmUksARfdVw9tuPf3CH/CohxO0Su1ApoKAeT6BVzAJIvjTuQVSmuQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"module-alias": "2.2.3",
|
||||
"node-ipc": "9.2.1",
|
||||
"ts-node": "10.9.2",
|
||||
"uuid": "10.0.0",
|
||||
"uuid": "11.0.1",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.16.11",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
|
||||
@@ -2393,6 +2393,20 @@
|
||||
"generateEmail": {
|
||||
"message": "Generate email"
|
||||
},
|
||||
"generatorBoundariesHint": {
|
||||
"message": "Value must be between $MIN$ and $MAX$",
|
||||
"description": "Explains spin box minimum and maximum values to the user",
|
||||
"placeholders": {
|
||||
"min": {
|
||||
"content": "$1",
|
||||
"example": "8"
|
||||
},
|
||||
"max": {
|
||||
"content": "$2",
|
||||
"example": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"usernameType": {
|
||||
"message": "Username type"
|
||||
},
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
"notifications": "https://notifications.usdev.bitwarden.pw",
|
||||
"scim": "https://scim.usdev.bitwarden.pw"
|
||||
},
|
||||
"additionalRegions": [
|
||||
{
|
||||
"key": "USDEV",
|
||||
"domain": "usdev.bitwarden.pw",
|
||||
"urls": {
|
||||
"webVault": "https://vault.usdev.bitwarden.pw"
|
||||
}
|
||||
}
|
||||
],
|
||||
"flags": {
|
||||
"showPasswordless": true
|
||||
}
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
<bit-tab [label]="'role' | i18n">
|
||||
<ng-container *ngIf="!editMode">
|
||||
<p bitTypography="body1">{{ "inviteUserDesc" | i18n }}</p>
|
||||
<bit-form-field>
|
||||
<bit-form-field *ngIf="remainingSeats$ | async as remainingSeats">
|
||||
<bit-label>{{ "email" | i18n }}</bit-label>
|
||||
<input id="emails" type="text" appAutoFocus bitInput formControlName="emails" />
|
||||
<bit-hint>{{
|
||||
"inviteMultipleEmailDesc"
|
||||
| i18n
|
||||
: (organization.productTierType === ProductTierType.TeamsStarter ? "10" : "20")
|
||||
<bit-hint *ngIf="remainingSeats > 1; else singleSeat">{{
|
||||
"inviteMultipleEmailDesc" | i18n: remainingSeats
|
||||
}}</bit-hint>
|
||||
<ng-template #singleSeat>
|
||||
<bit-hint>{{ "inviteSingleEmailDesc" | i18n: remainingSeats }}</bit-hint>
|
||||
</ng-template>
|
||||
</bit-form-field>
|
||||
</ng-container>
|
||||
<bit-radio-group formControlName="type">
|
||||
|
||||
@@ -89,6 +89,7 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
PermissionMode = PermissionMode;
|
||||
showNoMasterPasswordWarning = false;
|
||||
isOnSecretsManagerStandalone: boolean;
|
||||
remainingSeats$: Observable<number>;
|
||||
|
||||
protected organization$: Observable<Organization>;
|
||||
protected collectionAccessItems: AccessItemView[] = [];
|
||||
@@ -250,6 +251,10 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
this.remainingSeats$ = this.organization$.pipe(
|
||||
map((organization) => organization.seats - this.params.numConfirmedMembers),
|
||||
);
|
||||
}
|
||||
|
||||
private setFormValidators(organization: Organization) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button bitButton buttonType="primary" bitFormButton type="submit">
|
||||
<button bitButton buttonType="primary" [disabled]="saveDisabled" bitFormButton type="submit">
|
||||
{{ "save" | i18n }}
|
||||
</button>
|
||||
<button bitButton buttonType="secondary" bitDialogClose type="button">
|
||||
|
||||
@@ -42,6 +42,7 @@ export class PolicyEditComponent implements AfterViewInit {
|
||||
policyType = PolicyType;
|
||||
loading = true;
|
||||
enabled = false;
|
||||
saveDisabled = false;
|
||||
defaultTypes: any[];
|
||||
policyComponent: BasePolicyComponent;
|
||||
|
||||
@@ -72,6 +73,8 @@ export class PolicyEditComponent implements AfterViewInit {
|
||||
this.policyComponent.policy = this.data.policy;
|
||||
this.policyComponent.policyResponse = this.policyResponse;
|
||||
|
||||
this.saveDisabled = !this.policyResponse.canToggleState;
|
||||
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<bit-callout type="warning">
|
||||
{{ "singleOrgPolicyWarning" | i18n }}
|
||||
<bit-callout *ngIf="accountDeprovisioningEnabled$ | async; else disabledBlock" type="warning">
|
||||
{{ "singleOrgPolicyMemberWarning" | i18n }}
|
||||
</bit-callout>
|
||||
<ng-template #disabledBlock>
|
||||
<bit-callout type="warning">
|
||||
{{ "singleOrgPolicyWarning" | i18n }}
|
||||
</bit-callout>
|
||||
</ng-template>
|
||||
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox [formControl]="enabled" id="enabled" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request";
|
||||
@@ -19,7 +20,7 @@ export class SingleOrgPolicy extends BasePolicy {
|
||||
selector: "policy-single-org",
|
||||
templateUrl: "single-org.component.html",
|
||||
})
|
||||
export class SingleOrgPolicyComponent extends BasePolicyComponent {
|
||||
export class SingleOrgPolicyComponent extends BasePolicyComponent implements OnInit {
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private configService: ConfigService,
|
||||
@@ -27,6 +28,23 @@ export class SingleOrgPolicyComponent extends BasePolicyComponent {
|
||||
super();
|
||||
}
|
||||
|
||||
protected accountDeprovisioningEnabled$: Observable<boolean> = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
async ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
const isAccountDeprovisioningEnabled = await firstValueFrom(this.accountDeprovisioningEnabled$);
|
||||
this.policy.description = isAccountDeprovisioningEnabled
|
||||
? "singleOrgPolicyDesc"
|
||||
: "singleOrgDesc";
|
||||
|
||||
if (!this.policyResponse.canToggleState) {
|
||||
this.enabled.disable();
|
||||
}
|
||||
}
|
||||
|
||||
async buildRequest(policiesEnabledMap: Map<PolicyType, boolean>): Promise<PolicyRequest> {
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.Pm13322AddPolicyDefinitions)) {
|
||||
// We are now relying on server-side validation only
|
||||
@@ -48,6 +66,15 @@ export class SingleOrgPolicyComponent extends BasePolicyComponent {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$)) &&
|
||||
!this.policyResponse.canToggleState
|
||||
) {
|
||||
throw new Error(
|
||||
this.i18nService.t("disableRequiredError", this.i18nService.t("singleOrg")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return super.buildRequest(policiesEnabledMap);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" class="container" ngNativeValidate>
|
||||
<div class="row justify-content-md-center mt-5">
|
||||
<div class="col-5">
|
||||
<p class="lead text-center mb-4">{{ "deleteProvider" | i18n }}</p>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<app-callout type="warning">{{ "deleteProviderWarning" | i18n }}</app-callout>
|
||||
<p class="text-center">
|
||||
<strong>{{ name }}</strong>
|
||||
</p>
|
||||
<p>{{ "deleteProviderRecoverConfirmDesc" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="d-flex">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger btn-block btn-submit"
|
||||
[disabled]="form.loading"
|
||||
>
|
||||
<span>{{ "deleteProvider" | i18n }}</span>
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -3,7 +3,7 @@
|
||||
<bit-container>
|
||||
<app-profile></app-profile>
|
||||
|
||||
<div *ngIf="showChangeEmail" class="tw-mt-16">
|
||||
<div *ngIf="showChangeEmail$ | async" class="tw-mt-16">
|
||||
<h1 bitTypography="h1">{{ "changeEmail" | i18n }}</h1>
|
||||
<app-change-email></app-change-email>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { lastValueFrom, map, Observable, of, switchMap } from "rxjs";
|
||||
import { combineLatest, from, lastValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -21,7 +21,7 @@ export class AccountComponent implements OnInit {
|
||||
@ViewChild("deauthorizeSessionsTemplate", { read: ViewContainerRef, static: true })
|
||||
deauthModalRef: ViewContainerRef;
|
||||
|
||||
showChangeEmail = true;
|
||||
showChangeEmail$: Observable<boolean>;
|
||||
showPurgeVault$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
@@ -33,21 +33,36 @@ export class AccountComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.showChangeEmail = await this.userVerificationService.hasMasterPassword();
|
||||
this.showPurgeVault$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.AccountDeprovisioning)
|
||||
.pipe(
|
||||
switchMap((isAccountDeprovisioningEnabled) =>
|
||||
isAccountDeprovisioningEnabled
|
||||
? this.organizationService.organizations$.pipe(
|
||||
map(
|
||||
(organizations) =>
|
||||
!organizations.some((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
: of(true),
|
||||
),
|
||||
);
|
||||
const isAccountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
const userIsManagedByOrganization$ = this.organizationService.organizations$.pipe(
|
||||
map((organizations) => organizations.some((o) => o.userIsManagedByOrganization === true)),
|
||||
);
|
||||
|
||||
const hasMasterPassword$ = from(this.userVerificationService.hasMasterPassword());
|
||||
|
||||
this.showChangeEmail$ = combineLatest([
|
||||
hasMasterPassword$,
|
||||
isAccountDeprovisioningEnabled$,
|
||||
userIsManagedByOrganization$,
|
||||
]).pipe(
|
||||
map(
|
||||
([hasMasterPassword, isAccountDeprovisioningEnabled, userIsManagedByOrganization]) =>
|
||||
hasMasterPassword && (!isAccountDeprovisioningEnabled || !userIsManagedByOrganization),
|
||||
),
|
||||
);
|
||||
|
||||
this.showPurgeVault$ = combineLatest([
|
||||
isAccountDeprovisioningEnabled$,
|
||||
userIsManagedByOrganization$,
|
||||
]).pipe(
|
||||
map(
|
||||
([isAccountDeprovisioningEnabled, userIsManagedByOrganization]) =>
|
||||
!isAccountDeprovisioningEnabled || !userIsManagedByOrganization,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async deauthorizeSessions() {
|
||||
|
||||
@@ -40,7 +40,6 @@ import { flagEnabled, Flags } from "../utils/flags";
|
||||
import { VerifyRecoverDeleteOrgComponent } from "./admin-console/organizations/manage/verify-recover-delete-org.component";
|
||||
import { AcceptFamilySponsorshipComponent } from "./admin-console/organizations/sponsorships/accept-family-sponsorship.component";
|
||||
import { FamiliesForEnterpriseSetupComponent } from "./admin-console/organizations/sponsorships/families-for-enterprise-setup.component";
|
||||
import { VerifyRecoverDeleteProviderComponent } from "./admin-console/providers/verify-recover-delete-provider.component";
|
||||
import { CreateOrganizationComponent } from "./admin-console/settings/create-organization.component";
|
||||
import { deepLinkGuard } from "./auth/guards/deep-link.guard";
|
||||
import { HintComponent } from "./auth/hint.component";
|
||||
@@ -156,12 +155,6 @@ const routes: Routes = [
|
||||
canActivate: [unauthGuardFn()],
|
||||
data: { titleId: "deleteOrganization" },
|
||||
},
|
||||
{
|
||||
path: "verify-recover-delete-provider",
|
||||
component: VerifyRecoverDeleteProviderComponent,
|
||||
canActivate: [unauthGuardFn()],
|
||||
data: { titleId: "deleteAccount" } satisfies RouteDataProperties,
|
||||
},
|
||||
{
|
||||
path: "update-temp-password",
|
||||
component: UpdateTempPasswordComponent,
|
||||
|
||||
@@ -17,8 +17,6 @@ import { InactiveTwoFactorReportComponent as OrgInactiveTwoFactorReportComponent
|
||||
import { ReusedPasswordsReportComponent as OrgReusedPasswordsReportComponent } from "../admin-console/organizations/tools/reused-passwords-report.component";
|
||||
import { UnsecuredWebsitesReportComponent as OrgUnsecuredWebsitesReportComponent } from "../admin-console/organizations/tools/unsecured-websites-report.component";
|
||||
import { WeakPasswordsReportComponent as OrgWeakPasswordsReportComponent } from "../admin-console/organizations/tools/weak-passwords-report.component";
|
||||
import { ProvidersComponent } from "../admin-console/providers/providers.component";
|
||||
import { VerifyRecoverDeleteProviderComponent } from "../admin-console/providers/verify-recover-delete-provider.component";
|
||||
import { HintComponent } from "../auth/hint.component";
|
||||
import { RecoverDeleteComponent } from "../auth/recover-delete.component";
|
||||
import { RecoverTwoFactorComponent } from "../auth/recover-two-factor.component";
|
||||
@@ -149,7 +147,6 @@ import { SharedModule } from "./shared.module";
|
||||
PremiumBadgeComponent,
|
||||
ProfileComponent,
|
||||
ChangeAvatarDialogComponent,
|
||||
ProvidersComponent,
|
||||
PurgeVaultComponent,
|
||||
RecoverDeleteComponent,
|
||||
RecoverTwoFactorComponent,
|
||||
@@ -176,7 +173,6 @@ import { SharedModule } from "./shared.module";
|
||||
UpdateTempPasswordComponent,
|
||||
VerifyEmailTokenComponent,
|
||||
VerifyRecoverDeleteComponent,
|
||||
VerifyRecoverDeleteProviderComponent,
|
||||
],
|
||||
exports: [
|
||||
UserVerificationModule,
|
||||
@@ -218,7 +214,6 @@ import { SharedModule } from "./shared.module";
|
||||
PremiumBadgeComponent,
|
||||
ProfileComponent,
|
||||
ChangeAvatarDialogComponent,
|
||||
ProvidersComponent,
|
||||
PurgeVaultComponent,
|
||||
RecoverDeleteComponent,
|
||||
RecoverTwoFactorComponent,
|
||||
@@ -246,7 +241,6 @@ import { SharedModule } from "./shared.module";
|
||||
UserLayoutComponent,
|
||||
VerifyEmailTokenComponent,
|
||||
VerifyRecoverDeleteComponent,
|
||||
VerifyRecoverDeleteProviderComponent,
|
||||
HeaderModule,
|
||||
DangerZoneComponent,
|
||||
],
|
||||
|
||||
@@ -3214,6 +3214,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"inviteSingleEmailDesc": {
|
||||
"message": "You have 1 invite remaining."
|
||||
},
|
||||
"userUsingTwoStep": {
|
||||
"message": "This user is using two-step login to protect their account."
|
||||
},
|
||||
@@ -4681,12 +4684,18 @@
|
||||
"singleOrgDesc": {
|
||||
"message": "Restrict members from joining other organizations."
|
||||
},
|
||||
"singleOrgPolicyDesc": {
|
||||
"message": "Restrict members from joining other organizations. This policy is required for organizations that have enabled domain verification."
|
||||
},
|
||||
"singleOrgBlockCreateMessage": {
|
||||
"message": "Your current organization has a policy that does not allow you to join more than one organization. Please contact your organization admins or sign up from a different Bitwarden account."
|
||||
},
|
||||
"singleOrgPolicyWarning": {
|
||||
"message": "Organization members who are not owners or admins and are already a member of another organization will be removed from your organization."
|
||||
},
|
||||
"singleOrgPolicyMemberWarning": {
|
||||
"message": "Non-compliant members will be placed in revoked status until they leave all other organizations. Administrators are exempt and can restore members once compliance is met."
|
||||
},
|
||||
"requireSso": {
|
||||
"message": "Require single sign-on authentication"
|
||||
},
|
||||
@@ -6403,6 +6412,20 @@
|
||||
"generateEmail": {
|
||||
"message": "Generate email"
|
||||
},
|
||||
"generatorBoundariesHint": {
|
||||
"message": "Value must be between $MIN$ and $MAX$",
|
||||
"description": "Explains spin box minimum and maximum values to the user",
|
||||
"placeholders": {
|
||||
"min": {
|
||||
"content": "$1",
|
||||
"example": "8"
|
||||
},
|
||||
"max": {
|
||||
"content": "$2",
|
||||
"example": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"usernameType": {
|
||||
"message": "Username type"
|
||||
},
|
||||
@@ -9528,5 +9551,11 @@
|
||||
},
|
||||
"selfHostingTitleProper": {
|
||||
"message": "Self-Hosting"
|
||||
},
|
||||
"verified-domain-single-org-warning" : {
|
||||
"message": "Verifying a domain will turn on the single organization policy."
|
||||
},
|
||||
"single-org-revoked-user-warning": {
|
||||
"message": "Non-compliant members will be revoked. Administrators can restore members once they leave all other organizations."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Params } from "@angular/router";
|
||||
import { concatMap, Observable, Subject, take, takeUntil } from "rxjs";
|
||||
import {
|
||||
concatMap,
|
||||
firstValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
Subject,
|
||||
take,
|
||||
takeUntil,
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||
import { OrgDomainServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
||||
import { OrganizationDomainResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain.response";
|
||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
@@ -31,13 +41,13 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private orgDomainApiService: OrgDomainApiServiceAbstraction,
|
||||
private orgDomainService: OrgDomainServiceAbstraction,
|
||||
private dialogService: DialogService,
|
||||
private validationService: ValidationService,
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
@@ -64,13 +74,38 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
addDomain() {
|
||||
async addDomain() {
|
||||
const domainAddEditDialogData: DomainAddEditDialogData = {
|
||||
organizationId: this.organizationId,
|
||||
orgDomain: null,
|
||||
existingDomainNames: this.getExistingDomainNames(),
|
||||
};
|
||||
|
||||
await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning).pipe(
|
||||
withLatestFrom(this.orgDomains$),
|
||||
map(async ([accountDeprovisioningEnabled, organizationDomains]) => {
|
||||
if (
|
||||
accountDeprovisioningEnabled &&
|
||||
organizationDomains.every((domain) => domain.verifiedDate === null)
|
||||
) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "verified-domain-single-org-warning" },
|
||||
content: { key: "single-org-revoked-user-warning" },
|
||||
cancelButtonText: { key: "cancel" },
|
||||
acceptButtonText: { key: "confirm" },
|
||||
acceptAction: () => this.openAddDomainDialog(domainAddEditDialogData),
|
||||
type: "info",
|
||||
});
|
||||
} else {
|
||||
await this.openAddDomainDialog(domainAddEditDialogData);
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private async openAddDomainDialog(domainAddEditDialogData: DomainAddEditDialogData) {
|
||||
this.dialogService.open(DomainAddEditDialogComponent, {
|
||||
data: domainAddEditDialogData,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import { RouterModule, Routes } from "@angular/router";
|
||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
import { ProvidersComponent } from "@bitwarden/web-vault/app/admin-console/providers/providers.component";
|
||||
import { FrontendLayoutComponent } from "@bitwarden/web-vault/app/layouts/frontend-layout.component";
|
||||
import { UserLayoutComponent } from "@bitwarden/web-vault/app/layouts/user-layout.component";
|
||||
|
||||
@@ -22,6 +21,7 @@ import { AcceptProviderComponent } from "./manage/accept-provider.component";
|
||||
import { EventsComponent } from "./manage/events.component";
|
||||
import { MembersComponent } from "./manage/members.component";
|
||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||
import { ProvidersComponent } from "./providers.component";
|
||||
import { AccountComponent } from "./settings/account.component";
|
||||
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
||||
import { SetupComponent } from "./setup/setup.component";
|
||||
|
||||
@@ -32,10 +32,12 @@ import { MembersComponent } from "./manage/members.component";
|
||||
import { UserAddEditComponent } from "./manage/user-add-edit.component";
|
||||
import { ProvidersLayoutComponent } from "./providers-layout.component";
|
||||
import { ProvidersRoutingModule } from "./providers-routing.module";
|
||||
import { ProvidersComponent } from "./providers.component";
|
||||
import { WebProviderService } from "./services/web-provider.service";
|
||||
import { AccountComponent } from "./settings/account.component";
|
||||
import { SetupProviderComponent } from "./setup/setup-provider.component";
|
||||
import { SetupComponent } from "./setup/setup.component";
|
||||
import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-provider.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -73,6 +75,8 @@ import { SetupComponent } from "./setup/setup.component";
|
||||
ProviderBillingHistoryComponent,
|
||||
ProviderSubscriptionComponent,
|
||||
ProviderSubscriptionStatusComponent,
|
||||
ProvidersComponent,
|
||||
VerifyRecoverDeleteProviderComponent,
|
||||
],
|
||||
providers: [WebProviderService],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<p class="lead tw-text-center tw-mb-4">{{ "deleteProvider" | i18n }}</p>
|
||||
<app-callout type="warning">{{ "deleteProviderWarning" | i18n }}</app-callout>
|
||||
<p class="tw-text-center">
|
||||
<strong>{{ name }}</strong>
|
||||
</p>
|
||||
<p>{{ "deleteProviderRecoverConfirmDesc" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="tw-flex">
|
||||
<button bitButton [bitAction]="submit" buttonType="danger" type="button" [block]="true">
|
||||
<span>{{ "deleteProvider" | i18n }}</span>
|
||||
</button>
|
||||
<a routerLink="/login" bitButton buttonType="secondary" [block]="true" class="tw-ml-2 tw-mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -5,8 +5,6 @@ import { firstValueFrom } from "rxjs";
|
||||
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
|
||||
import { ProviderVerifyRecoverDeleteRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-verify-recover-delete.request";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
@@ -16,7 +14,6 @@ import { ToastService } from "@bitwarden/components";
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class VerifyRecoverDeleteProviderComponent implements OnInit {
|
||||
name: string;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
private providerId: string;
|
||||
private token: string;
|
||||
@@ -24,10 +21,8 @@ export class VerifyRecoverDeleteProviderComponent implements OnInit {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private providerApiService: ProviderApiServiceAbstraction,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private route: ActivatedRoute,
|
||||
private logService: LogService,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
|
||||
@@ -42,22 +37,14 @@ export class VerifyRecoverDeleteProviderComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
const request = new ProviderVerifyRecoverDeleteRequest(this.token);
|
||||
this.formPromise = this.providerApiService.providerRecoverDeleteToken(
|
||||
this.providerId,
|
||||
request,
|
||||
);
|
||||
await this.formPromise;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: this.i18nService.t("providerDeleted"),
|
||||
message: this.i18nService.t("providerDeletedDesc"),
|
||||
});
|
||||
await this.router.navigate(["/"]);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
submit = async () => {
|
||||
const request = new ProviderVerifyRecoverDeleteRequest(this.token);
|
||||
await this.providerApiService.providerRecoverDeleteToken(this.providerId, request);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: this.i18nService.t("providerDeleted"),
|
||||
message: this.i18nService.t("providerDeletedDesc"),
|
||||
});
|
||||
await this.router.navigate(["/"]);
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { unauthGuardFn } from "@bitwarden/angular/auth/guards";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
||||
import { deepLinkGuard } from "@bitwarden/web-vault/app/auth/guards/deep-link.guard";
|
||||
import { RouteDataProperties } from "@bitwarden/web-vault/app/core";
|
||||
|
||||
import { ProvidersModule } from "./admin-console/providers/providers.module";
|
||||
import { VerifyRecoverDeleteProviderComponent } from "./admin-console/providers/verify-recover-delete-provider.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -17,6 +21,18 @@ const routes: Routes = [
|
||||
loadChildren: async () =>
|
||||
(await import("./secrets-manager/secrets-manager.module")).SecretsManagerModule,
|
||||
},
|
||||
{
|
||||
path: "verify-recover-delete-provider",
|
||||
component: AnonLayoutWrapperComponent,
|
||||
canActivate: [unauthGuardFn()],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
component: VerifyRecoverDeleteProviderComponent,
|
||||
data: { titleId: "deleteAccount" } satisfies RouteDataProperties,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -18,7 +18,8 @@ import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstraction
|
||||
import { CaptchaIFrame } from "@bitwarden/common/auth/captcha-iframe";
|
||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { ClientType, HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
@@ -26,6 +27,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
@@ -136,6 +138,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
private syncService: SyncService,
|
||||
private toastService: ToastService,
|
||||
private logService: LogService,
|
||||
private validationService: ValidationService,
|
||||
) {
|
||||
this.clientType = this.platformUtilsService.getClientType();
|
||||
this.loginViaAuthRequestSupported = this.loginComponentService.isLoginViaAuthRequestSupported();
|
||||
@@ -182,19 +185,54 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
null,
|
||||
);
|
||||
|
||||
const authResult = await this.loginStrategyService.logIn(credentials);
|
||||
try {
|
||||
const authResult = await this.loginStrategyService.logIn(credentials);
|
||||
|
||||
await this.saveEmailSettings();
|
||||
await this.handleAuthResult(authResult);
|
||||
await this.saveEmailSettings();
|
||||
await this.handleAuthResult(authResult);
|
||||
|
||||
if (this.clientType === ClientType.Desktop) {
|
||||
if (this.captchaSiteKey) {
|
||||
const content = document.getElementById("content") as HTMLDivElement;
|
||||
content.setAttribute("style", "width:335px");
|
||||
if (this.clientType === ClientType.Desktop) {
|
||||
if (this.captchaSiteKey) {
|
||||
const content = document.getElementById("content") as HTMLDivElement;
|
||||
content.setAttribute("style", "width:335px");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
this.handleSubmitError(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the error from the submit function.
|
||||
*
|
||||
* @param error The error object.
|
||||
*/
|
||||
private handleSubmitError(error: unknown) {
|
||||
// Handle error responses
|
||||
if (error instanceof ErrorResponse) {
|
||||
switch (error.statusCode) {
|
||||
case HttpStatusCode.BadRequest: {
|
||||
if (error.message.toLowerCase().includes("username or password is incorrect")) {
|
||||
this.formGroup.controls.masterPassword.setErrors({
|
||||
error: {
|
||||
message: this.i18nService.t("invalidMasterPassword"),
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Allow all other errors to be handled by toast
|
||||
this.validationService.showError(error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Allow all other errors to be handled by toast
|
||||
this.validationService.showError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the authentication process.
|
||||
*
|
||||
|
||||
@@ -8,6 +8,7 @@ export class PolicyResponse extends BaseResponse {
|
||||
type: PolicyType;
|
||||
data: any;
|
||||
enabled: boolean;
|
||||
canToggleState: boolean;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -16,5 +17,6 @@ export class PolicyResponse extends BaseResponse {
|
||||
this.type = this.getResponseProperty("Type");
|
||||
this.data = this.getResponseProperty("Data");
|
||||
this.enabled = this.getResponseProperty("Enabled");
|
||||
this.canToggleState = this.getResponseProperty("CanToggleState") ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ export class DefaultSdkService implements SdkService {
|
||||
let client: BitwardenClient;
|
||||
|
||||
const createAndInitializeClient = async () => {
|
||||
if (privateKey == null || userKey == null || orgKeys == null) {
|
||||
if (privateKey == null || userKey == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ export class DefaultSdkService implements SdkService {
|
||||
kdfParams: KdfConfig,
|
||||
privateKey: EncryptedString,
|
||||
userKey: UserKey,
|
||||
orgKeys: Record<OrganizationId, EncryptedOrganizationKeyData>,
|
||||
orgKeys?: Record<OrganizationId, EncryptedOrganizationKeyData>,
|
||||
) {
|
||||
await client.crypto().initialize_user_crypto({
|
||||
email: account.email,
|
||||
@@ -169,9 +169,12 @@ export class DefaultSdkService implements SdkService {
|
||||
},
|
||||
privateKey,
|
||||
});
|
||||
|
||||
// We initialize the org crypto even if the org_keys are
|
||||
// null to make sure any existing org keys are cleared.
|
||||
await client.crypto().initialize_org_crypto({
|
||||
organizationKeys: new Map(
|
||||
Object.entries(orgKeys)
|
||||
Object.entries(orgKeys ?? {})
|
||||
.filter(([_, v]) => v.type === "organization")
|
||||
.map(([k, v]) => [k, v.key]),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<bit-card *ngFor="let credential of credentials$ | async" class="tw-mb-2">
|
||||
<div class="tw-flex tw-justify-between tw-items-center">
|
||||
<div class="tw-flex tw-flex-col">
|
||||
<h2 bitTypography="h6">{{ credential.credential }}</h2>
|
||||
<bit-color-password
|
||||
class="tw-font-mono"
|
||||
[password]="credential.credential"
|
||||
></bit-color-password>
|
||||
<span class="tw-text-muted" bitTypography="body1">{{
|
||||
credential.generationDate | date: "medium"
|
||||
}}</span>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
CardComponent,
|
||||
ColorPasswordModule,
|
||||
IconButtonModule,
|
||||
NoItemsModule,
|
||||
SectionComponent,
|
||||
@@ -21,6 +22,7 @@ import { GeneratedCredential, GeneratorHistoryService } from "@bitwarden/generat
|
||||
selector: "bit-credential-generator-history",
|
||||
templateUrl: "credential-generator-history.component.html",
|
||||
imports: [
|
||||
ColorPasswordModule,
|
||||
CommonModule,
|
||||
IconButtonModule,
|
||||
NoItemsModule,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "numWords" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="numWords" id="num-words" type="number" />
|
||||
<bit-hint>{{ numWordsBoundariesHint$ | async }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { OnInit, Input, Output, EventEmitter, Component, OnDestroy } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { BehaviorSubject, skip, takeUntil, Subject } from "rxjs";
|
||||
import { BehaviorSubject, skip, takeUntil, Subject, ReplaySubject } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
Generators,
|
||||
@@ -29,11 +30,13 @@ export class PassphraseSettingsComponent implements OnInit, OnDestroy {
|
||||
/** Instantiates the component
|
||||
* @param accountService queries user availability
|
||||
* @param generatorService settings and policy logic
|
||||
* @param i18nService localize hints
|
||||
* @param formBuilder reactive form controls
|
||||
*/
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private generatorService: CredentialGeneratorService,
|
||||
private i18nService: I18nService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
@@ -97,6 +100,13 @@ export class PassphraseSettingsComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.toggleEnabled(Controls.capitalize, !constraints.capitalize?.readonly);
|
||||
this.toggleEnabled(Controls.includeNumber, !constraints.includeNumber?.readonly);
|
||||
|
||||
const boundariesHint = this.i18nService.t(
|
||||
"generatorBoundariesHint",
|
||||
constraints.numWords.min,
|
||||
constraints.numWords.max,
|
||||
);
|
||||
this.numWordsBoundariesHint.next(boundariesHint);
|
||||
});
|
||||
|
||||
// now that outputs are set up, connect inputs
|
||||
@@ -106,6 +116,11 @@ export class PassphraseSettingsComponent implements OnInit, OnDestroy {
|
||||
/** display binding for enterprise policy notice */
|
||||
protected policyInEffect: boolean;
|
||||
|
||||
private numWordsBoundariesHint = new ReplaySubject<string>(1);
|
||||
|
||||
/** display binding for min/max constraints of `numWords` */
|
||||
protected numWordsBoundariesHint$ = this.numWordsBoundariesHint.asObservable();
|
||||
|
||||
private toggleEnabled(setting: keyof typeof Controls, enabled: boolean) {
|
||||
if (enabled) {
|
||||
this.settings.get(setting).enable({ emitEvent: false });
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "length" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="length" type="number" />
|
||||
<bit-hint>{{ lengthBoundariesHint$ | async }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { OnInit, Input, Output, EventEmitter, Component, OnDestroy } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { BehaviorSubject, takeUntil, Subject, map, filter, tap, skip } from "rxjs";
|
||||
import { BehaviorSubject, takeUntil, Subject, map, filter, tap, skip, ReplaySubject } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
Generators,
|
||||
@@ -33,11 +34,13 @@ export class PasswordSettingsComponent implements OnInit, OnDestroy {
|
||||
/** Instantiates the component
|
||||
* @param accountService queries user availability
|
||||
* @param generatorService settings and policy logic
|
||||
* @param i18nService localize hints
|
||||
* @param formBuilder reactive form controls
|
||||
*/
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private generatorService: CredentialGeneratorService,
|
||||
private i18nService: I18nService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
@@ -147,6 +150,13 @@ export class PasswordSettingsComponent implements OnInit, OnDestroy {
|
||||
for (const [control, enabled] of toggles) {
|
||||
this.toggleEnabled(control, enabled);
|
||||
}
|
||||
|
||||
const boundariesHint = this.i18nService.t(
|
||||
"generatorBoundariesHint",
|
||||
constraints.length.min,
|
||||
constraints.length.max,
|
||||
);
|
||||
this.lengthBoundariesHint.next(boundariesHint);
|
||||
});
|
||||
|
||||
// cascade selections between checkboxes and spinboxes
|
||||
@@ -208,6 +218,11 @@ export class PasswordSettingsComponent implements OnInit, OnDestroy {
|
||||
/** display binding for enterprise policy notice */
|
||||
protected policyInEffect: boolean;
|
||||
|
||||
private lengthBoundariesHint = new ReplaySubject<string>(1);
|
||||
|
||||
/** display binding for min/max constraints of `length` */
|
||||
protected lengthBoundariesHint$ = this.lengthBoundariesHint.asObservable();
|
||||
|
||||
private toggleEnabled(setting: keyof typeof Controls, enabled: boolean) {
|
||||
if (enabled) {
|
||||
this.settings.get(setting).enable({ emitEvent: false });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { BehaviorSubject, skip, Subject, takeUntil } from "rxjs";
|
||||
import { BehaviorSubject, map, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
@@ -53,9 +53,23 @@ export class SubaddressSettingsComponent implements OnInit, OnDestroy {
|
||||
const singleUserId$ = this.singleUserId$();
|
||||
const settings = await this.generatorService.settings(Generators.subaddress, { singleUserId$ });
|
||||
|
||||
settings.pipe(takeUntil(this.destroyed$)).subscribe((s) => {
|
||||
this.settings.patchValue(s, { emitEvent: false });
|
||||
});
|
||||
settings
|
||||
.pipe(
|
||||
withLatestFrom(this.accountService.activeAccount$),
|
||||
map(([settings, activeAccount]) => {
|
||||
// if the subaddress isn't specified, copy it from
|
||||
// the user's settings
|
||||
if ((settings.subaddressEmail ?? "").length < 1) {
|
||||
settings.subaddressEmail = activeAccount.email;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}),
|
||||
takeUntil(this.destroyed$),
|
||||
)
|
||||
.subscribe((s) => {
|
||||
this.settings.patchValue(s, { emitEvent: false });
|
||||
});
|
||||
|
||||
// the first emission is the current value; subsequent emissions are updates
|
||||
settings.pipe(skip(1), takeUntil(this.destroyed$)).subscribe(this.onUpdated);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<button
|
||||
*ngIf="hasPassword"
|
||||
class="tw-border-l-0 last:tw-rounded-r focus-visible:tw-border-l focus-visible:tw-ml-[-1px]"
|
||||
bitSuffix
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
bitIconButton="bwi-minus-circle"
|
||||
|
||||
192
package-lock.json
generated
192
package-lock.json
generated
@@ -68,7 +68,7 @@
|
||||
"qrious": "4.0.2",
|
||||
"rxjs": "7.8.1",
|
||||
"tabbable": "6.2.0",
|
||||
"tldts": "6.1.52",
|
||||
"tldts": "6.1.56",
|
||||
"utf-8-validate": "6.0.4",
|
||||
"zone.js": "0.13.3",
|
||||
"zxcvbn": "4.4.2"
|
||||
@@ -110,7 +110,7 @@
|
||||
"@types/koa-json": "2.0.23",
|
||||
"@types/lowdb": "1.0.15",
|
||||
"@types/lunr": "2.3.7",
|
||||
"@types/node": "20.16.11",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node-fetch": "2.6.4",
|
||||
"@types/node-forge": "1.3.11",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
@@ -121,7 +121,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "7.16.1",
|
||||
"@typescript-eslint/parser": "7.16.1",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"@yao-pkg/pkg": "5.14.0",
|
||||
"@yao-pkg/pkg": "5.16.1",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.1.3",
|
||||
"base64-loader": "1.0.0",
|
||||
@@ -225,7 +225,7 @@
|
||||
"papaparse": "5.4.1",
|
||||
"proper-lockfile": "4.1.2",
|
||||
"rxjs": "7.8.1",
|
||||
"tldts": "6.1.52",
|
||||
"tldts": "6.1.56",
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
"bin": {
|
||||
@@ -9642,9 +9642,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.16.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz",
|
||||
"integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==",
|
||||
"version": "20.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz",
|
||||
"integrity": "sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -11069,42 +11069,40 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-5.14.0.tgz",
|
||||
"integrity": "sha512-34oflUyAOI64a4cc4AF3ckvS8Qqnk/ISvZ1bDBa1/JAYaaFtzAO+RlhPaU+wCHzhk6VXvZwEywJpb+SlVDTgdA==",
|
||||
"version": "5.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-5.16.1.tgz",
|
||||
"integrity": "sha512-crUlnNFSReFNFuXDc4f3X2ignkFlc9kmEG7Bp/mJMA1jYyqR0lqjZGLgrSDYTYiNsYud8AzgA3RY1DrMdcUZWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/generator": "7.23.0",
|
||||
"@babel/parser": "7.23.0",
|
||||
"@babel/types": "7.23.0",
|
||||
"@yao-pkg/pkg-fetch": "3.5.11",
|
||||
"chalk": "^4.1.2",
|
||||
"fs-extra": "^9.1.0",
|
||||
"globby": "^11.1.0",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"@yao-pkg/pkg-fetch": "3.5.16",
|
||||
"into-stream": "^6.0.0",
|
||||
"minimatch": "9.0.4",
|
||||
"minimist": "^1.2.6",
|
||||
"multistream": "^4.1.0",
|
||||
"prebuild-install": "7.1.1",
|
||||
"picocolors": "^1.1.0",
|
||||
"picomatch": "^4.0.2",
|
||||
"prebuild-install": "^7.1.1",
|
||||
"resolve": "^1.22.0",
|
||||
"stream-meter": "^1.0.4"
|
||||
"stream-meter": "^1.0.4",
|
||||
"tinyglobby": "^0.2.9"
|
||||
},
|
||||
"bin": {
|
||||
"pkg": "lib-es5/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg-fetch": {
|
||||
"version": "3.5.11",
|
||||
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.11.tgz",
|
||||
"integrity": "sha512-2tQ/1n7BLTptW6lL0pfTCnVMIxls8Jiw0/ClK1J2Fja9z2S2j4uzNL5dwGRqtvPJPn/q9i8X+Y+c4dwnMb+NOA==",
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.16.tgz",
|
||||
"integrity": "sha512-mCnZvZz0/Ylpk4TGyt34pqWJyBGYJM8c3dPoMRV8Knodv2QhcYS4iXb5kB/JNWkrRtCKukGZIKkMLXZ3TQlzPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"fs-extra": "^9.1.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"node-fetch": "^2.6.6",
|
||||
"picocolors": "^1.1.0",
|
||||
"progress": "^2.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tar-fs": "^2.1.1",
|
||||
@@ -11126,22 +11124,6 @@
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg-fetch/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg-fetch/node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
@@ -11204,79 +11186,45 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg/node_modules/@babel/generator": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
|
||||
"integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
"@babel/types": "^7.25.7",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg/node_modules/@babel/parser": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"node_modules/@yao-pkg/pkg/node_modules/jsesc": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
|
||||
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg/node_modules/@babel/types": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"node_modules/@yao-pkg/pkg/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@yao-pkg/pkg/node_modules/minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@yarnpkg/fslib": {
|
||||
@@ -36428,6 +36376,48 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.9.tgz",
|
||||
"integrity": "sha512-8or1+BGEdk1Zkkw2ii16qSS7uVrQJPre5A9o/XkWPATkk23FZh/15BKFxPnlTy6vkljZxLqYCzzBMj30ZrSvjw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.0",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
|
||||
"integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyspy": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
|
||||
@@ -36439,21 +36429,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tldts": {
|
||||
"version": "6.1.52",
|
||||
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.52.tgz",
|
||||
"integrity": "sha512-fgrDJXDjbAverY6XnIt0lNfv8A0cf7maTEaZxNykLGsLG7XP+5xhjBTrt/ieAsFjAlZ+G5nmXomLcZDkxXnDzw==",
|
||||
"version": "6.1.56",
|
||||
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.56.tgz",
|
||||
"integrity": "sha512-2PT1oRZCxtsbLi5R2SQjE/v4vvgRggAtVcYj+3Rrcnu2nPZvu7m64+gDa/EsVSWd3QzEc0U0xN+rbEKsJC47kA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tldts-core": "^6.1.52"
|
||||
"tldts-core": "^6.1.56"
|
||||
},
|
||||
"bin": {
|
||||
"tldts": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tldts-core": {
|
||||
"version": "6.1.52",
|
||||
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.52.tgz",
|
||||
"integrity": "sha512-j4OxQI5rc1Ve/4m/9o2WhWSC4jGc4uVbCINdOEJRAraCi0YqTqgMcxUx7DbmuP0G3PCixoof/RZB0Q5Kh9tagw==",
|
||||
"version": "6.1.56",
|
||||
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.56.tgz",
|
||||
"integrity": "sha512-Ihxv/Bwiyj73icTYVgBUkQ3wstlCglLoegSgl64oSrGUBX1hc7Qmf/CnrnJLaQdZrCnTaLqMYOwKMKlkfkFrxQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
"@types/koa-json": "2.0.23",
|
||||
"@types/lowdb": "1.0.15",
|
||||
"@types/lunr": "2.3.7",
|
||||
"@types/node": "20.16.11",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node-fetch": "2.6.4",
|
||||
"@types/node-forge": "1.3.11",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
@@ -82,7 +82,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "7.16.1",
|
||||
"@typescript-eslint/parser": "7.16.1",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"@yao-pkg/pkg": "5.14.0",
|
||||
"@yao-pkg/pkg": "5.16.1",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.1.3",
|
||||
"base64-loader": "1.0.0",
|
||||
@@ -202,7 +202,7 @@
|
||||
"qrious": "4.0.2",
|
||||
"rxjs": "7.8.1",
|
||||
"tabbable": "6.2.0",
|
||||
"tldts": "6.1.52",
|
||||
"tldts": "6.1.56",
|
||||
"utf-8-validate": "6.0.4",
|
||||
"zone.js": "0.13.3",
|
||||
"zxcvbn": "4.4.2"
|
||||
|
||||
Reference in New Issue
Block a user