1
0
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:
Victoria League
2024-10-28 16:00:40 -04:00
committed by GitHub
41 changed files with 457 additions and 240 deletions

View File

@@ -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"
},

View File

@@ -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"
}
}

View File

@@ -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",

View File

@@ -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]

View File

@@ -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": {

View File

@@ -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"
},

View File

@@ -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"
},

View File

@@ -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
}

View File

@@ -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">

View File

@@ -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) {

View File

@@ -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">

View File

@@ -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();
}

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>

View File

@@ -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() {

View File

@@ -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,

View File

@@ -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,
],

View File

@@ -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."
}
}

View File

@@ -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,
});

View File

@@ -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";

View File

@@ -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],
})

View File

@@ -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>

View File

@@ -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(["/"]);
};
}

View File

@@ -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({

View File

@@ -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.
*

View File

@@ -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;
}
}

View File

@@ -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]),
),

View File

@@ -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>

View File

@@ -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,

View File

@@ -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>

View File

@@ -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 });

View File

@@ -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>

View File

@@ -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 });

View File

@@ -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);

View File

@@ -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
View File

@@ -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": {

View File

@@ -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"