mirror of
https://github.com/bitwarden/browser
synced 2026-02-28 02:23:25 +00:00
Merge branch 'master' into auth/pm-3797/emergency-access-refactor
This commit is contained in:
@@ -45,10 +45,20 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: "tools",
|
||||
loadChildren: () =>
|
||||
import("../tools/import-export/org-import-export.module").then(
|
||||
(m) => m.OrganizationImportExportModule
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: "import",
|
||||
loadChildren: () =>
|
||||
import("../tools/import/org-import.module").then((m) => m.OrganizationImportModule),
|
||||
},
|
||||
{
|
||||
path: "export",
|
||||
loadChildren: () =>
|
||||
import("../tools/vault-export/org-vault-export.module").then(
|
||||
(m) => m.OrganizationVaultExportModule
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -15,15 +15,17 @@ import { ValidationService } from "@bitwarden/common/platform/abstractions/valid
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { OrganizationPlansComponent } from "../../../billing/settings/organization-plans.component";
|
||||
import { OrganizationPlansComponent } from "../../../billing";
|
||||
import { SharedModule } from "../../../shared";
|
||||
import {
|
||||
DeleteOrganizationDialogResult,
|
||||
openDeleteOrganizationDialog,
|
||||
} from "../settings/components";
|
||||
|
||||
@Component({
|
||||
selector: "families-for-enterprise-setup",
|
||||
templateUrl: "families-for-enterprise-setup.component.html",
|
||||
standalone: true,
|
||||
imports: [SharedModule, OrganizationPlansComponent],
|
||||
})
|
||||
export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(OrganizationPlansComponent, { static: false })
|
||||
|
||||
@@ -6,9 +6,9 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../../reports/pages/exposed-passwords-report.component";
|
||||
|
||||
@@ -3,14 +3,13 @@ import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
|
||||
import { OrganizationPermissionsGuard } from "../../../../admin-console/organizations/guards/org-permissions.guard";
|
||||
import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard";
|
||||
|
||||
import { OrganizationExportComponent } from "./org-export.component";
|
||||
import { OrganizationImportComponent } from "./org-import.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "import",
|
||||
path: "",
|
||||
component: OrganizationImportComponent,
|
||||
canActivate: [OrganizationPermissionsGuard],
|
||||
data: {
|
||||
@@ -18,18 +17,9 @@ const routes: Routes = [
|
||||
organizationPermissions: (org: Organization) => org.canAccessImportExport,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "export",
|
||||
component: OrganizationExportComponent,
|
||||
canActivate: [OrganizationPermissionsGuard],
|
||||
data: {
|
||||
titleId: "exportVault",
|
||||
organizationPermissions: (org: Organization) => org.canAccessImportExport,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
})
|
||||
export class OrganizationImportExportRoutingModule {}
|
||||
export class OrganizationImportRoutingModule {}
|
||||
@@ -18,11 +18,11 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { ImportServiceAbstraction } from "@bitwarden/importer";
|
||||
|
||||
import { ImportComponent } from "../../../../tools/import-export/import.component";
|
||||
import { ImportComponent } from "../../../../tools/import/import.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-import",
|
||||
templateUrl: "../../../../tools/import-export/import.component.html",
|
||||
templateUrl: "../../../../tools/import/import.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class OrganizationImportComponent extends ImportComponent {
|
||||
@@ -15,13 +15,12 @@ import {
|
||||
|
||||
import { LooseComponentsModule, SharedModule } from "../../../../shared";
|
||||
|
||||
import { OrganizationExportComponent } from "./org-export.component";
|
||||
import { OrganizationImportExportRoutingModule } from "./org-import-export-routing.module";
|
||||
import { OrganizationImportRoutingModule } from "./org-import-routing.module";
|
||||
import { OrganizationImportComponent } from "./org-import.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, LooseComponentsModule, OrganizationImportExportRoutingModule],
|
||||
declarations: [OrganizationImportComponent, OrganizationExportComponent],
|
||||
imports: [SharedModule, LooseComponentsModule, OrganizationImportRoutingModule],
|
||||
declarations: [OrganizationImportComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: ImportApiServiceAbstraction,
|
||||
@@ -42,4 +41,4 @@ import { OrganizationImportComponent } from "./org-import.component";
|
||||
},
|
||||
],
|
||||
})
|
||||
export class OrganizationImportExportModule {}
|
||||
export class OrganizationImportModule {}
|
||||
@@ -6,8 +6,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../../reports/pages/inactive-two-factor-report.component";
|
||||
|
||||
@@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../../reports/pages/reused-passwords-report.component";
|
||||
|
||||
@@ -5,8 +5,8 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../../reports/pages/unsecured-websites-report.component";
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
|
||||
import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard";
|
||||
|
||||
import { OrganizationVaultExportComponent } from "./org-vault-export.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
component: OrganizationVaultExportComponent,
|
||||
canActivate: [OrganizationPermissionsGuard],
|
||||
data: {
|
||||
titleId: "exportVault",
|
||||
organizationPermissions: (org: Organization) => org.canAccessImportExport,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
})
|
||||
export class OrganizationVaultExportRoutingModule {}
|
||||
@@ -14,14 +14,14 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export";
|
||||
|
||||
import { ExportComponent } from "../../../../tools/import-export/export.component";
|
||||
import { ExportComponent } from "../../../../tools/vault-export/export.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-export",
|
||||
templateUrl: "../../../../tools/import-export/export.component.html",
|
||||
templateUrl: "../../../../tools/vault-export/export.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class OrganizationExportComponent extends ExportComponent {
|
||||
export class OrganizationVaultExportComponent extends ExportComponent {
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
i18nService: I18nService,
|
||||
@@ -0,0 +1,12 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { LooseComponentsModule, SharedModule } from "../../../../shared";
|
||||
|
||||
import { OrganizationVaultExportRoutingModule } from "./org-vault-export-routing.module";
|
||||
import { OrganizationVaultExportComponent } from "./org-vault-export.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, LooseComponentsModule, OrganizationVaultExportRoutingModule],
|
||||
declarations: [OrganizationVaultExportComponent],
|
||||
})
|
||||
export class OrganizationVaultExportModule {}
|
||||
@@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../../reports/pages/weak-passwords-report.component";
|
||||
|
||||
@@ -5,11 +5,13 @@ import { first } from "rxjs/operators";
|
||||
import { PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
|
||||
import { OrganizationPlansComponent } from "../../billing/settings/organization-plans.component";
|
||||
import { OrganizationPlansComponent } from "../../billing";
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
@Component({
|
||||
selector: "app-create-organization",
|
||||
templateUrl: "create-organization.component.html",
|
||||
standalone: true,
|
||||
imports: [SharedModule, OrganizationPlansComponent],
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class CreateOrganizationComponent implements OnInit {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { CoreAuthModule } from "./core";
|
||||
import { SettingsModule } from "./settings/settings.module";
|
||||
import { AuthSettingsModule } from "./settings/settings.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [CoreAuthModule, SettingsModule],
|
||||
imports: [AuthSettingsModule],
|
||||
declarations: [],
|
||||
providers: [],
|
||||
exports: [SettingsModule],
|
||||
exports: [AuthSettingsModule],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from "./services";
|
||||
export * from "./core.module";
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
import { SaveCredentialRequest } from "./request/save-credential.request";
|
||||
import { WebauthnLoginCredentialCreateOptionsResponse } from "./response/webauthn-login-credential-create-options.response";
|
||||
import { WebauthnLoginCredentialResponse } from "./response/webauthn-login-credential.response";
|
||||
|
||||
@Injectable()
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class WebauthnLoginApiService {
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private userVerificationService: UserVerificationService
|
||||
) {}
|
||||
constructor(private apiService: ApiService) {}
|
||||
|
||||
async getCredentialCreateOptions(
|
||||
verification: Verification
|
||||
request: SecretVerificationRequest
|
||||
): Promise<WebauthnLoginCredentialCreateOptionsResponse> {
|
||||
const request = await this.userVerificationService.buildRequest(verification);
|
||||
const response = await this.apiService.send("POST", "/webauthn/options", request, true, true);
|
||||
return new WebauthnLoginCredentialCreateOptionsResponse(response);
|
||||
}
|
||||
@@ -33,8 +28,7 @@ export class WebauthnLoginApiService {
|
||||
return this.apiService.send("GET", "/webauthn", null, true, true);
|
||||
}
|
||||
|
||||
async deleteCredential(credentialId: string, verification: Verification): Promise<void> {
|
||||
const request = await this.userVerificationService.buildRequest(verification);
|
||||
async deleteCredential(credentialId: string, request: SecretVerificationRequest): Promise<void> {
|
||||
await this.apiService.send("POST", `/webauthn/${credentialId}/delete`, request, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
|
||||
import { CredentialCreateOptionsView } from "../../views/credential-create-options.view";
|
||||
|
||||
import { WebauthnLoginApiService } from "./webauthn-login-api.service";
|
||||
@@ -7,6 +9,7 @@ import { WebauthnLoginService } from "./webauthn-login.service";
|
||||
|
||||
describe("WebauthnService", () => {
|
||||
let apiService!: MockProxy<WebauthnLoginApiService>;
|
||||
let userVerificationService!: MockProxy<UserVerificationService>;
|
||||
let credentials: MockProxy<CredentialsContainer>;
|
||||
let webauthnService!: WebauthnLoginService;
|
||||
|
||||
@@ -15,8 +18,9 @@ describe("WebauthnService", () => {
|
||||
window.PublicKeyCredential = class {} as any;
|
||||
window.AuthenticatorAttestationResponse = class {} as any;
|
||||
apiService = mock<WebauthnLoginApiService>();
|
||||
userVerificationService = mock<UserVerificationService>();
|
||||
credentials = mock<CredentialsContainer>();
|
||||
webauthnService = new WebauthnLoginService(apiService, credentials);
|
||||
webauthnService = new WebauthnLoginService(apiService, userVerificationService, credentials);
|
||||
});
|
||||
|
||||
describe("createCredential", () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, Optional } from "@angular/core";
|
||||
import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, tap } from "rxjs";
|
||||
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
@@ -11,8 +12,10 @@ import { SaveCredentialRequest } from "./request/save-credential.request";
|
||||
import { WebauthnLoginAttestationResponseRequest } from "./request/webauthn-login-attestation-response.request";
|
||||
import { WebauthnLoginApiService } from "./webauthn-login-api.service";
|
||||
|
||||
@Injectable()
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class WebauthnLoginService {
|
||||
static readonly MaxCredentialCount = 5;
|
||||
|
||||
private navigatorCredentials: CredentialsContainer;
|
||||
private _refresh$ = new BehaviorSubject<void>(undefined);
|
||||
private _loading$ = new BehaviorSubject<boolean>(true);
|
||||
@@ -27,6 +30,7 @@ export class WebauthnLoginService {
|
||||
|
||||
constructor(
|
||||
private apiService: WebauthnLoginApiService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
@Optional() navigatorCredentials?: CredentialsContainer,
|
||||
@Optional() private logService?: LogService
|
||||
) {
|
||||
@@ -37,7 +41,8 @@ export class WebauthnLoginService {
|
||||
async getCredentialCreateOptions(
|
||||
verification: Verification
|
||||
): Promise<CredentialCreateOptionsView> {
|
||||
const response = await this.apiService.getCredentialCreateOptions(verification);
|
||||
const request = await this.userVerificationService.buildRequest(verification);
|
||||
const response = await this.apiService.getCredentialCreateOptions(request);
|
||||
return new CredentialCreateOptionsView(response.options, response.token);
|
||||
}
|
||||
|
||||
@@ -95,7 +100,8 @@ export class WebauthnLoginService {
|
||||
}
|
||||
|
||||
async deleteCredential(credentialId: string, verification: Verification): Promise<void> {
|
||||
await this.apiService.deleteCredential(credentialId, verification);
|
||||
const request = await this.userVerificationService.buildRequest(verification);
|
||||
await this.apiService.deleteCredential(credentialId, request);
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from "../../../vault/individual-vault/add-edit.component";
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { PasswordCalloutComponent } from "@bitwarden/auth";
|
||||
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
import { ChangePasswordComponent } from "./change-password.component";
|
||||
import { WebauthnLoginSettingsModule } from "./webauthn-login-settings";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, WebauthnLoginSettingsModule],
|
||||
imports: [SharedModule, WebauthnLoginSettingsModule, PasswordCalloutComponent],
|
||||
declarations: [ChangePasswordComponent],
|
||||
providers: [],
|
||||
exports: [WebauthnLoginSettingsModule, ChangePasswordComponent],
|
||||
exports: [ChangePasswordComponent],
|
||||
})
|
||||
export class SettingsModule {}
|
||||
export class AuthSettingsModule {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog dialogSize="large">
|
||||
<bit-dialog dialogSize="large" [loading]="loading$ | async">
|
||||
<span bitDialogTitle
|
||||
>{{ "loginWithPasskey" | i18n }}
|
||||
<span class="tw-text-sm tw-normal-case tw-text-muted">{{ "newPasskey" | i18n }}</span>
|
||||
|
||||
@@ -46,6 +46,7 @@ export class CreateCredentialDialogComponent implements OnInit {
|
||||
protected credentialOptions?: CredentialCreateOptionsView;
|
||||
protected deviceResponse?: PublicKeyCredential;
|
||||
protected hasPasskeys$?: Observable<boolean>;
|
||||
protected loading$ = this.webauthnService.loading$;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
@@ -144,7 +145,7 @@ export class CreateCredentialDialogComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstValueFrom(this.hasPasskeys$)) {
|
||||
if (await firstValueFrom(this.hasPasskeys$)) {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog dialogSize="large">
|
||||
<bit-dialog dialogSize="large" [loading]="loading$ | async">
|
||||
<span bitDialogTitle
|
||||
>{{ "removePasskey" | i18n }}
|
||||
<span *ngIf="credential" class="tw-text-sm tw-normal-case tw-text-muted">{{
|
||||
|
||||
@@ -27,6 +27,7 @@ export class DeleteCredentialDialogComponent implements OnInit, OnDestroy {
|
||||
masterPassword: ["", [Validators.required]],
|
||||
});
|
||||
protected credential?: WebauthnCredentialView;
|
||||
protected loading$ = this.webauthnService.loading$;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) private params: DeleteCredentialDialogParams,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<table *ngIf="hasCredentials" class="tw-mb-5">
|
||||
<tr *ngFor="let credential of credentials">
|
||||
<td class="tw-p-2 tw-pl-0 tw-font-semibold">{{ credential.name }}</td>
|
||||
<td class="tw-p-2 tw-pr-0">
|
||||
<td class="tw-p-2 tw-pr-10">
|
||||
<ng-container *ngIf="credential.prfSupport">
|
||||
<i class="bwi bwi-lock-encrypted"></i>
|
||||
{{ "supportsEncryption" | i18n }}
|
||||
@@ -31,7 +31,7 @@
|
||||
{{ "encryptionNotSupported" | i18n }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="tw-py-2 tw-pl-10 tw-pr-0">
|
||||
<td class="tw-py-2">
|
||||
<button
|
||||
type="button"
|
||||
bitLink
|
||||
|
||||
@@ -19,7 +19,7 @@ import { openDeleteCredentialDialogComponent } from "./delete-credential-dialog/
|
||||
export class WebauthnLoginSettingsComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
protected readonly MaxCredentialCount = 5;
|
||||
protected readonly MaxCredentialCount = WebauthnLoginService.MaxCredentialCount;
|
||||
|
||||
protected credentials?: WebauthnCredentialView[];
|
||||
protected loading = true;
|
||||
|
||||
@@ -6,9 +6,10 @@ import { FormFieldModule } from "@bitwarden/components";
|
||||
|
||||
import { OrganizationCreateModule } from "../../admin-console/organizations/create/organization-create.module";
|
||||
import { RegisterFormModule } from "../../auth/register-form/register-form.module";
|
||||
import { PaymentComponent, TaxInfoComponent } from "../../billing";
|
||||
import { BillingComponent } from "../../billing/accounts/trial-initiation/billing.component";
|
||||
import { EnvironmentSelectorModule } from "../../components/environment-selector/environment-selector.module";
|
||||
import { LooseComponentsModule, SharedModule } from "../../shared";
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
import { ConfirmationDetailsComponent } from "./confirmation-details.component";
|
||||
import { AbmEnterpriseContentComponent } from "./content/abm-enterprise-content.component";
|
||||
@@ -37,8 +38,9 @@ import { VerticalStepperModule } from "./vertical-stepper/vertical-stepper.modul
|
||||
FormFieldModule,
|
||||
RegisterFormModule,
|
||||
OrganizationCreateModule,
|
||||
LooseComponentsModule,
|
||||
EnvironmentSelectorModule,
|
||||
PaymentComponent,
|
||||
TaxInfoComponent,
|
||||
],
|
||||
declarations: [
|
||||
TrialInitiationComponent,
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<div id="duo-frame" class="mb-3">
|
||||
<iframe
|
||||
id="duo_iframe"
|
||||
sandbox="allow-scripts allow-forms allow-same-origin"
|
||||
sandbox="allow-scripts allow-forms allow-same-origin allow-popups allow-popups-to-escape-sandbox"
|
||||
></iframe>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FormGroup } from "@angular/forms";
|
||||
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
|
||||
import { OrganizationPlansComponent } from "../../settings/organization-plans.component";
|
||||
import { OrganizationPlansComponent } from "../../organizations";
|
||||
|
||||
@Component({
|
||||
selector: "app-billing",
|
||||
|
||||
2
apps/web/src/app/billing/index.ts
Normal file
2
apps/web/src/app/billing/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { OrganizationPlansComponent } from "./organizations";
|
||||
export { PaymentComponent, TaxInfoComponent } from "./shared";
|
||||
@@ -6,7 +6,6 @@ import { BillingHistoryResponse } from "@bitwarden/common/billing/models/respons
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-billing-history-view",
|
||||
templateUrl: "billing-history-view.component.html",
|
||||
})
|
||||
export class BillingHistoryViewComponent implements OnInit {
|
||||
0
apps/web/src/app/billing/individual/index.ts
Normal file
0
apps/web/src/app/billing/individual/index.ts
Normal file
@@ -1,12 +1,12 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { BillingHistoryViewComponent } from "../../billing/settings/billing-history-view.component";
|
||||
import { PaymentMethodComponent } from "../../billing/settings/payment-method.component";
|
||||
import { UserSubscriptionComponent } from "../../billing/settings/user-subscription.component";
|
||||
import { PremiumComponent } from "../settings/premium.component";
|
||||
import { PaymentMethodComponent } from "../shared";
|
||||
|
||||
import { BillingHistoryViewComponent } from "./billing-history-view.component";
|
||||
import { PremiumComponent } from "./premium.component";
|
||||
import { SubscriptionComponent } from "./subscription.component";
|
||||
import { UserSubscriptionComponent } from "./user-subscription.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -43,4 +43,4 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class SubscriptionRoutingModule {}
|
||||
export class IndividualBillingRoutingModule {}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { BillingSharedModule } from "../shared";
|
||||
|
||||
import { BillingHistoryViewComponent } from "./billing-history-view.component";
|
||||
import { IndividualBillingRoutingModule } from "./individual-billing-routing.module";
|
||||
import { PremiumComponent } from "./premium.component";
|
||||
import { SubscriptionComponent } from "./subscription.component";
|
||||
import { UserSubscriptionComponent } from "./user-subscription.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [IndividualBillingRoutingModule, BillingSharedModule],
|
||||
declarations: [
|
||||
SubscriptionComponent,
|
||||
BillingHistoryViewComponent,
|
||||
UserSubscriptionComponent,
|
||||
PremiumComponent,
|
||||
],
|
||||
})
|
||||
export class IndividualBillingModule {}
|
||||
@@ -11,11 +11,9 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
|
||||
import { PaymentComponent } from "./payment.component";
|
||||
import { TaxInfoComponent } from "./tax-info.component";
|
||||
import { PaymentComponent, TaxInfoComponent } from "../shared";
|
||||
|
||||
@Component({
|
||||
selector: "app-premium",
|
||||
templateUrl: "premium.component.html",
|
||||
})
|
||||
export class PremiumComponent implements OnInit {
|
||||
@@ -4,7 +4,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-subscription",
|
||||
templateUrl: "subscription.component.html",
|
||||
})
|
||||
export class SubscriptionComponent {
|
||||
@@ -12,7 +12,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
selector: "app-user-subscription",
|
||||
templateUrl: "user-subscription.component.html",
|
||||
})
|
||||
export class UserSubscriptionComponent implements OnInit {
|
||||
@@ -14,7 +14,7 @@
|
||||
required
|
||||
/>
|
||||
<small class="d-block text-muted mb-4">
|
||||
<strong>{{ "total" | i18n }}:</strong> {{ newSeatCount || 0 }} ×
|
||||
<strong>{{ "total" | i18n }}:</strong> {{ additionalSeatCount || 0 }} ×
|
||||
{{ seatPrice | currency : "$" }} = {{ adjustedSeatTotal | currency : "$" }} /
|
||||
{{ interval | i18n }}
|
||||
</small>
|
||||
@@ -50,7 +50,7 @@
|
||||
[required]="limitSubscription"
|
||||
/>
|
||||
<small class="d-block text-muted">
|
||||
<strong>{{ "maxSeatCost" | i18n }}:</strong> {{ newMaxSeats || 0 }} ×
|
||||
<strong>{{ "maxSeatCost" | i18n }}:</strong> {{ additionalMaxSeatCount || 0 }} ×
|
||||
{{ seatPrice | currency : "$" }} = {{ maxSeatTotal | currency : "$" }} /
|
||||
{{ interval | i18n }}
|
||||
</small>
|
||||
|
||||
@@ -38,8 +38,10 @@ export class AdjustSubscription {
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
const seatAdjustment = this.newSeatCount - this.currentSeatCount;
|
||||
const request = new OrganizationSubscriptionUpdateRequest(seatAdjustment, this.newMaxSeats);
|
||||
const request = new OrganizationSubscriptionUpdateRequest(
|
||||
this.additionalSeatCount,
|
||||
this.newMaxSeats
|
||||
);
|
||||
this.formPromise = this.organizationApiService.updatePasswordManagerSeats(
|
||||
this.organizationId,
|
||||
request
|
||||
@@ -64,11 +66,19 @@ export class AdjustSubscription {
|
||||
}
|
||||
}
|
||||
|
||||
get additionalSeatCount(): number {
|
||||
return this.newSeatCount ? this.newSeatCount - this.currentSeatCount : 0;
|
||||
}
|
||||
|
||||
get additionalMaxSeatCount(): number {
|
||||
return this.newMaxSeats ? this.newMaxSeats - this.currentSeatCount : 0;
|
||||
}
|
||||
|
||||
get adjustedSeatTotal(): number {
|
||||
return this.newSeatCount * this.seatPrice;
|
||||
return this.additionalSeatCount * this.seatPrice;
|
||||
}
|
||||
|
||||
get maxSeatTotal(): number {
|
||||
return this.newMaxSeats * this.seatPrice;
|
||||
return this.additionalMaxSeatCount * this.seatPrice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +1,75 @@
|
||||
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="billingSyncApiKeyTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<form
|
||||
class="modal-content"
|
||||
#form
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
ngNativeValidate
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title" id="billingSyncApiKeyTitle">
|
||||
{{ (hasBillingToken ? "viewBillingSyncToken" : "generateBillingSyncToken") | i18n }}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
appA11yTitle="{{ 'close' | i18n }}"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<app-user-verification
|
||||
[(ngModel)]="masterPassword"
|
||||
ngDefaultControl
|
||||
name="secret"
|
||||
*ngIf="!clientSecret"
|
||||
>
|
||||
</app-user-verification>
|
||||
<ng-container *ngIf="clientSecret && showRotateScreen">
|
||||
<p>{{ "rotateBillingSyncTokenTitle" | i18n }}</p>
|
||||
<app-callout type="warning">
|
||||
{{ "rotateBillingSyncTokenWarning" | i18n }}
|
||||
</app-callout>
|
||||
</ng-container>
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog>
|
||||
<h1 bitDialogTitle>
|
||||
{{ (hasBillingToken ? "viewBillingSyncToken" : "generateBillingSyncToken") | i18n }}
|
||||
</h1>
|
||||
<div bitDialogContent>
|
||||
<app-user-verification formControlName="verification" *ngIf="!clientSecret">
|
||||
</app-user-verification>
|
||||
|
||||
<div *ngIf="clientSecret && !showRotateScreen">
|
||||
<p>{{ "copyPasteBillingSync" | i18n }}</p>
|
||||
<label for="clientSecret">{{ "billingSyncKey" | i18n }}</label>
|
||||
<div class="input-group">
|
||||
<input
|
||||
id="clientSecret"
|
||||
class="form-control text-monospace"
|
||||
type="text"
|
||||
[(ngModel)]="clientSecret"
|
||||
name="clientSecret"
|
||||
disabled
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
(click)="copy()"
|
||||
[appA11yTitle]="'copy' | i18n"
|
||||
>
|
||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="small text-muted mt-2" *ngIf="showLastSyncText">
|
||||
<b class="font-weight-semibold">{{ "lastSync" | i18n }}:</b>
|
||||
{{ lastSyncDate | date : "medium" }}
|
||||
</div>
|
||||
<div class="small text-danger mt-2" *ngIf="showAwaitingSyncText">
|
||||
<i class="bwi bwi-error"></i>
|
||||
{{
|
||||
(daysBetween === 1 ? "awaitingSyncSingular" : "awaitingSyncPlural")
|
||||
| i18n : daysBetween
|
||||
}}
|
||||
</div>
|
||||
<ng-container *ngIf="clientSecret && showRotateScreen">
|
||||
<p>{{ "rotateBillingSyncTokenTitle" | i18n }}</p>
|
||||
<bit-callout type="warning">
|
||||
{{ "rotateBillingSyncTokenWarning" | i18n }}
|
||||
</bit-callout>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="clientSecret && !showRotateScreen">
|
||||
<p>{{ "copyPasteBillingSync" | i18n }}</p>
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "billingSyncKey" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
id="clientSecret"
|
||||
type="text"
|
||||
[value]="clientSecret"
|
||||
class="tw-font-mono"
|
||||
disabled
|
||||
/>
|
||||
<button
|
||||
bitIconButton="bwi-clone"
|
||||
bitSuffix
|
||||
type="button"
|
||||
[appCopyClick]="clientSecret"
|
||||
[appA11yTitle]="'copyValue' | i18n"
|
||||
></button>
|
||||
</bit-form-field>
|
||||
<div class="tw-mt-2 tw-text-sm tw-text-muted" *ngIf="showLastSyncText">
|
||||
<b class="tw-font-semibold">{{ "lastSync" | i18n }}:</b>
|
||||
{{ lastSyncDate | date : "medium" }}
|
||||
</div>
|
||||
<div class="tw-mt-2 tw-text-sm tw-text-danger" *ngIf="showAwaitingSyncText">
|
||||
<i class="bwi bwi-error"></i>
|
||||
{{
|
||||
(daysBetween === 1 ? "awaitingSyncSingular" : "awaitingSyncPlural") | i18n : daysBetween
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-submit"
|
||||
[disabled]="form.loading"
|
||||
*ngIf="!clientSecret || showRotateScreen"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
*ngIf="form.loading"
|
||||
></i>
|
||||
<span>
|
||||
{{ submitButtonText }}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
data-dismiss="modal"
|
||||
*ngIf="!showRotateScreen"
|
||||
>
|
||||
{{ "close" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
*ngIf="showRotateScreen"
|
||||
(click)="cancelRotate()"
|
||||
>
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
*ngIf="clientSecret && !showRotateScreen"
|
||||
(click)="rotateToken()"
|
||||
>
|
||||
{{ "rotateToken" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container bitDialogFooter>
|
||||
<button
|
||||
type="submit"
|
||||
bitButton
|
||||
bitFormButton
|
||||
buttonType="primary"
|
||||
*ngIf="!clientSecret || showRotateScreen"
|
||||
>
|
||||
{{ submitButtonText }}
|
||||
</button>
|
||||
<button bitButton bitDialogClose type="button" *ngIf="!showRotateScreen">
|
||||
{{ "close" | i18n }}
|
||||
</button>
|
||||
<button bitButton type="button" *ngIf="showRotateScreen" (click)="cancelRotate()">
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
bitButton
|
||||
type="button"
|
||||
*ngIf="clientSecret && !showRotateScreen"
|
||||
(click)="rotateToken()"
|
||||
>
|
||||
{{ "rotateToken" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
</form>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
|
||||
import { ModalConfig } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationApiKeyType } from "@bitwarden/common/admin-console/enums";
|
||||
@@ -8,8 +9,10 @@ import { OrganizationApiKeyRequest } from "@bitwarden/common/admin-console/model
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { ApiKeyResponse } from "@bitwarden/common/auth/models/response/api-key.response";
|
||||
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 { Verification } from "@bitwarden/common/types/verification";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
export interface BillingSyncApiModalData {
|
||||
organizationId: string;
|
||||
@@ -17,63 +20,69 @@ export interface BillingSyncApiModalData {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "app-billing-sync-api-key",
|
||||
templateUrl: "billing-sync-api-key.component.html",
|
||||
})
|
||||
export class BillingSyncApiKeyComponent {
|
||||
organizationId: string;
|
||||
hasBillingToken: boolean;
|
||||
protected organizationId: string;
|
||||
protected hasBillingToken: boolean;
|
||||
|
||||
protected formGroup = new FormGroup({
|
||||
verification: new FormControl<Verification>(null, Validators.required),
|
||||
});
|
||||
|
||||
showRotateScreen: boolean;
|
||||
masterPassword: Verification;
|
||||
formPromise: Promise<ApiKeyResponse>;
|
||||
clientSecret?: string;
|
||||
keyRevisionDate?: Date;
|
||||
lastSyncDate?: Date = null;
|
||||
lastSyncDate?: Date;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected data: BillingSyncApiModalData,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private apiService: ApiService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
modalConfig: ModalConfig<BillingSyncApiModalData>
|
||||
private logService: LogService
|
||||
) {
|
||||
this.organizationId = modalConfig.data.organizationId;
|
||||
this.hasBillingToken = modalConfig.data.hasBillingToken;
|
||||
this.organizationId = data.organizationId;
|
||||
this.hasBillingToken = data.hasBillingToken;
|
||||
}
|
||||
|
||||
copy() {
|
||||
this.platformUtilsService.copyToClipboard(this.clientSecret);
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (this.showRotateScreen) {
|
||||
this.formPromise = this.userVerificationService
|
||||
.buildRequest(this.masterPassword, OrganizationApiKeyRequest)
|
||||
submit = async () => {
|
||||
try {
|
||||
const request = this.userVerificationService
|
||||
.buildRequest(this.formGroup.value.verification, OrganizationApiKeyRequest)
|
||||
.then((request) => {
|
||||
request.type = OrganizationApiKeyType.BillingSync;
|
||||
return request;
|
||||
});
|
||||
|
||||
if (this.showRotateScreen) {
|
||||
const response = await request.then((request) => {
|
||||
return this.organizationApiService.rotateApiKey(this.organizationId, request);
|
||||
});
|
||||
const response = await this.formPromise;
|
||||
await this.load(response);
|
||||
this.showRotateScreen = false;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("billingSyncApiKeyRotated")
|
||||
);
|
||||
} else {
|
||||
this.formPromise = this.userVerificationService
|
||||
.buildRequest(this.masterPassword, OrganizationApiKeyRequest)
|
||||
.then((request) => {
|
||||
request.type = OrganizationApiKeyType.BillingSync;
|
||||
await this.load(response);
|
||||
this.showRotateScreen = false;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("billingSyncApiKeyRotated")
|
||||
);
|
||||
} else {
|
||||
const response = await request.then((request) => {
|
||||
return this.organizationApiService.getOrCreateApiKey(this.organizationId, request);
|
||||
});
|
||||
const response = await this.formPromise;
|
||||
await this.load(response);
|
||||
await this.load(response);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async load(response: ApiKeyResponse) {
|
||||
this.clientSecret = response.apiKey;
|
||||
@@ -117,4 +126,8 @@ export class BillingSyncApiKeyComponent {
|
||||
get daysBetween(): number {
|
||||
return this.dayDiff(this.keyRevisionDate, new Date());
|
||||
}
|
||||
|
||||
static open(dialogService: DialogService, data: BillingSyncApiModalData) {
|
||||
return dialogService.open(BillingSyncApiKeyComponent, { data });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ export interface BillingSyncKeyModalData {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "app-billing-sync-key",
|
||||
templateUrl: "billing-sync-key.component.html",
|
||||
})
|
||||
export class BillingSyncKeyComponent {
|
||||
1
apps/web/src/app/billing/organizations/index.ts
Normal file
1
apps/web/src/app/billing/organizations/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./organization-plans.component";
|
||||
@@ -6,7 +6,6 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
|
||||
import { BillingHistoryResponse } from "@bitwarden/common/billing/models/response/billing-history.response";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-billing-history-view",
|
||||
templateUrl: "organization-billing-history-view.component.html",
|
||||
})
|
||||
export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
|
||||
|
||||
@@ -5,8 +5,8 @@ import { canAccessBillingTab } from "@bitwarden/common/admin-console/abstraction
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
|
||||
import { OrganizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard";
|
||||
import { PaymentMethodComponent } from "../../billing/settings/payment-method.component";
|
||||
import { WebPlatformUtilsService } from "../../core/web-platform-utils.service";
|
||||
import { PaymentMethodComponent } from "../shared";
|
||||
|
||||
import { OrgBillingHistoryViewComponent } from "./organization-billing-history-view.component";
|
||||
import { OrganizationBillingTabComponent } from "./organization-billing-tab.component";
|
||||
|
||||
@@ -6,7 +6,6 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-billing-tab",
|
||||
templateUrl: "organization-billing-tab.component.html",
|
||||
})
|
||||
export class OrganizationBillingTabComponent implements OnInit {
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { UserVerificationModule } from "../../auth/shared/components/user-verification";
|
||||
import { LooseComponentsModule, SharedModule } from "../../shared";
|
||||
import { BillingSharedModule } from "../shared";
|
||||
|
||||
import { AdjustSubscription } from "./adjust-subscription.component";
|
||||
import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
|
||||
import { BillingSyncKeyComponent } from "./billing-sync-key.component";
|
||||
import { ChangePlanComponent } from "./change-plan.component";
|
||||
import { DownloadLicenseComponent } from "./download-license.component";
|
||||
import { OrgBillingHistoryViewComponent } from "./organization-billing-history-view.component";
|
||||
import { OrganizationBillingRoutingModule } from "./organization-billing-routing.module";
|
||||
import { OrganizationBillingTabComponent } from "./organization-billing-tab.component";
|
||||
import { OrganizationPlansComponent } from "./organization-plans.component";
|
||||
import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component";
|
||||
import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component";
|
||||
import { SecretsManagerBillingModule } from "./secrets-manager/sm-billing.module";
|
||||
import { SecretsManagerAdjustSubscriptionComponent } from "./sm-adjust-subscription.component";
|
||||
import { SecretsManagerSubscribeStandaloneComponent } from "./sm-subscribe-standalone.component";
|
||||
import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
LooseComponentsModule,
|
||||
OrganizationBillingRoutingModule,
|
||||
UserVerificationModule,
|
||||
SecretsManagerBillingModule,
|
||||
BillingSharedModule,
|
||||
OrganizationPlansComponent,
|
||||
],
|
||||
declarations: [
|
||||
AdjustSubscription,
|
||||
BillingSyncApiKeyComponent,
|
||||
BillingSyncKeyComponent,
|
||||
ChangePlanComponent,
|
||||
DownloadLicenseComponent,
|
||||
OrganizationBillingTabComponent,
|
||||
OrgBillingHistoryViewComponent,
|
||||
OrganizationSubscriptionSelfhostComponent,
|
||||
OrganizationSubscriptionCloudComponent,
|
||||
OrganizationSubscriptionSelfhostComponent,
|
||||
OrgBillingHistoryViewComponent,
|
||||
SecretsManagerAdjustSubscriptionComponent,
|
||||
SecretsManagerSubscribeStandaloneComponent,
|
||||
SubscriptionHiddenComponent,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -276,7 +276,7 @@
|
||||
<!-- Secrets Manager -->
|
||||
<div class="tw-my-10">
|
||||
<sm-subscribe
|
||||
*ngIf="planOffersSecretsManager"
|
||||
*ngIf="planOffersSecretsManager && !hasProvider"
|
||||
[formGroup]="formGroup.controls.secretsManager"
|
||||
[selectedPlan]="selectedSecretsManagerPlan"
|
||||
[upgradeOrganization]="!createOrganization"
|
||||
@@ -35,10 +35,10 @@ import {
|
||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
|
||||
import { secretsManagerSubscribeFormFactory } from "../organizations/secrets-manager/sm-subscribe.component";
|
||||
|
||||
import { PaymentComponent } from "./payment.component";
|
||||
import { TaxInfoComponent } from "./tax-info.component";
|
||||
import { OrganizationCreateModule } from "../../admin-console/organizations/create/organization-create.module";
|
||||
import { BillingSharedModule, secretsManagerSubscribeFormFactory } from "../shared";
|
||||
import { PaymentComponent } from "../shared/payment.component";
|
||||
import { TaxInfoComponent } from "../shared/tax-info.component";
|
||||
|
||||
interface OnSuccessArgs {
|
||||
organizationId: string;
|
||||
@@ -47,6 +47,8 @@ interface OnSuccessArgs {
|
||||
@Component({
|
||||
selector: "app-organization-plans",
|
||||
templateUrl: "organization-plans.component.html",
|
||||
standalone: true,
|
||||
imports: [BillingSharedModule, OrganizationCreateModule],
|
||||
})
|
||||
export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
|
||||
@@ -146,7 +148,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.providerId) {
|
||||
if (this.hasProvider) {
|
||||
this.formGroup.controls.businessOwned.setValue(true);
|
||||
this.changedOwnedBusiness();
|
||||
}
|
||||
@@ -174,7 +176,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get singleOrgPolicyBlock() {
|
||||
return this.singleOrgPolicyAppliesToActiveUser && this.providerId == null;
|
||||
return this.singleOrgPolicyAppliesToActiveUser && !this.hasProvider;
|
||||
}
|
||||
|
||||
get createOrganization() {
|
||||
@@ -233,6 +235,10 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
get hasProvider() {
|
||||
return this.providerId != null;
|
||||
}
|
||||
|
||||
additionalStoragePriceMonthly(selectedPlan: PlanResponse) {
|
||||
if (!selectedPlan.isAnnual) {
|
||||
return selectedPlan.additionalStoragePricePerGb;
|
||||
@@ -538,7 +544,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
// Secrets Manager
|
||||
this.buildSecretsManagerRequest(request);
|
||||
|
||||
if (this.providerId) {
|
||||
if (this.hasProvider) {
|
||||
const providerRequest = new ProviderOrganizationCreateRequest(
|
||||
this.formGroup.controls.clientOwnerEmail.value,
|
||||
request
|
||||
@@ -1,9 +1,8 @@
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, Subject, takeUntil } from "rxjs";
|
||||
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ModalConfig, ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -18,14 +17,10 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
BillingSyncApiKeyComponent,
|
||||
BillingSyncApiModalData,
|
||||
} from "./billing-sync-api-key.component";
|
||||
import { SecretsManagerSubscriptionOptions } from "./secrets-manager/sm-adjust-subscription.component";
|
||||
import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
|
||||
import { SecretsManagerSubscriptionOptions } from "./sm-adjust-subscription.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-subscription-cloud",
|
||||
templateUrl: "organization-subscription-cloud.component.html",
|
||||
})
|
||||
export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy {
|
||||
@@ -55,7 +50,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private logService: LogService,
|
||||
private modalService: ModalService,
|
||||
private organizationService: OrganizationService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private route: ActivatedRoute,
|
||||
@@ -116,6 +110,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
|
||||
this.showSecretsManagerSubscribe =
|
||||
this.userOrg.canEditSubscription &&
|
||||
!this.userOrg.hasProvider &&
|
||||
!this.userOrg.useSecretsManager &&
|
||||
!this.subscription?.cancelled &&
|
||||
!this.subscriptionMarkedForCancel;
|
||||
@@ -330,22 +325,13 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
}
|
||||
|
||||
async manageBillingSync() {
|
||||
const modalConfig: ModalConfig<BillingSyncApiModalData> = {
|
||||
data: {
|
||||
organizationId: this.organizationId,
|
||||
hasBillingToken: this.hasBillingSyncToken,
|
||||
},
|
||||
};
|
||||
const modalRef = this.modalService.open(BillingSyncApiKeyComponent, modalConfig);
|
||||
const dialogRef = BillingSyncApiKeyComponent.open(this.dialogService, {
|
||||
organizationId: this.organizationId,
|
||||
hasBillingToken: this.hasBillingSyncToken,
|
||||
});
|
||||
|
||||
modalRef.onClosed
|
||||
.pipe(
|
||||
concatMap(async () => {
|
||||
this.load();
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe();
|
||||
await firstValueFrom(dialogRef.closed);
|
||||
this.load();
|
||||
}
|
||||
|
||||
closeDownloadLicense() {
|
||||
|
||||
@@ -17,10 +17,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import {
|
||||
BillingSyncKeyComponent,
|
||||
BillingSyncKeyModalData,
|
||||
} from "../../billing/settings/billing-sync-key.component";
|
||||
import { BillingSyncKeyComponent, BillingSyncKeyModalData } from "./billing-sync-key.component";
|
||||
|
||||
enum LicenseOptions {
|
||||
SYNC = 0,
|
||||
@@ -28,7 +25,6 @@ enum LicenseOptions {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "app-org-subscription-selfhost",
|
||||
templateUrl: "organization-subscription-selfhost.component.html",
|
||||
})
|
||||
export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDestroy {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from "./sm-billing.module";
|
||||
export * from "./sm-subscribe.component";
|
||||
export * from "./sm-subscribe-standalone.component";
|
||||
@@ -1,22 +0,0 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { SharedModule } from "../../../shared";
|
||||
|
||||
import { SecretsManagerAdjustSubscriptionComponent } from "./sm-adjust-subscription.component";
|
||||
import { SecretsManagerSubscribeStandaloneComponent } from "./sm-subscribe-standalone.component";
|
||||
import { SecretsManagerSubscribeComponent } from "./sm-subscribe.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule],
|
||||
declarations: [
|
||||
SecretsManagerSubscribeComponent,
|
||||
SecretsManagerSubscribeStandaloneComponent,
|
||||
SecretsManagerAdjustSubscriptionComponent,
|
||||
],
|
||||
exports: [
|
||||
SecretsManagerSubscribeComponent,
|
||||
SecretsManagerSubscribeStandaloneComponent,
|
||||
SecretsManagerAdjustSubscriptionComponent,
|
||||
],
|
||||
})
|
||||
export class SecretsManagerBillingModule {}
|
||||
@@ -10,7 +10,7 @@ import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.res
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { secretsManagerSubscribeFormFactory } from "./sm-subscribe.component";
|
||||
import { secretsManagerSubscribeFormFactory } from "../shared";
|
||||
|
||||
@Component({
|
||||
selector: "sm-subscribe-standalone",
|
||||
@@ -9,7 +9,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { PaymentComponent } from "../billing/settings/payment.component";
|
||||
import { PaymentComponent } from "./payment.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-adjust-storage",
|
||||
37
apps/web/src/app/billing/shared/billing-shared.module.ts
Normal file
37
apps/web/src/app/billing/shared/billing-shared.module.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
import { AddCreditComponent } from "./add-credit.component";
|
||||
import { AdjustPaymentComponent } from "./adjust-payment.component";
|
||||
import { AdjustStorageComponent } from "./adjust-storage.component";
|
||||
import { BillingHistoryComponent } from "./billing-history.component";
|
||||
import { PaymentMethodComponent } from "./payment-method.component";
|
||||
import { PaymentComponent } from "./payment.component";
|
||||
import { SecretsManagerSubscribeComponent } from "./sm-subscribe.component";
|
||||
import { TaxInfoComponent } from "./tax-info.component";
|
||||
import { UpdateLicenseComponent } from "./update-license.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, PaymentComponent, TaxInfoComponent],
|
||||
declarations: [
|
||||
AddCreditComponent,
|
||||
AdjustPaymentComponent,
|
||||
AdjustStorageComponent,
|
||||
BillingHistoryComponent,
|
||||
PaymentMethodComponent,
|
||||
SecretsManagerSubscribeComponent,
|
||||
UpdateLicenseComponent,
|
||||
],
|
||||
exports: [
|
||||
SharedModule,
|
||||
PaymentComponent,
|
||||
TaxInfoComponent,
|
||||
|
||||
AdjustStorageComponent,
|
||||
BillingHistoryComponent,
|
||||
SecretsManagerSubscribeComponent,
|
||||
UpdateLicenseComponent,
|
||||
],
|
||||
})
|
||||
export class BillingSharedModule {}
|
||||
5
apps/web/src/app/billing/shared/index.ts
Normal file
5
apps/web/src/app/billing/shared/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from "./billing-shared.module";
|
||||
export * from "./payment-method.component";
|
||||
export * from "./payment.component";
|
||||
export * from "./sm-subscribe.component";
|
||||
export * from "./tax-info.component";
|
||||
@@ -17,7 +17,6 @@ import { DialogService } from "@bitwarden/components";
|
||||
import { TaxInfoComponent } from "./tax-info.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-payment-method",
|
||||
templateUrl: "payment-method.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
@@ -6,9 +6,13 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
@Component({
|
||||
selector: "app-payment",
|
||||
templateUrl: "payment.component.html",
|
||||
standalone: true,
|
||||
imports: [SharedModule],
|
||||
})
|
||||
export class PaymentComponent implements OnInit, OnDestroy {
|
||||
@Input() showMethods = true;
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox formControlName="enabled" />
|
||||
<bit-label>{{ "addSecretsManager" | i18n }}</bit-label>
|
||||
<bit-label>{{ "subscribeToSecretsManager" | i18n }}</bit-label>
|
||||
<bit-hint *ngIf="upgradeOrganization">{{ "addSecretsManagerUpgradeDesc" | i18n }}</bit-hint>
|
||||
</bit-form-control>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.res
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { SecretsManagerLogo } from "../../../layouts/secrets-manager-logo";
|
||||
import { SecretsManagerLogo } from "../../layouts/secrets-manager-logo";
|
||||
|
||||
export interface SecretsManagerSubscription {
|
||||
enabled: boolean;
|
||||
@@ -9,6 +9,8 @@ import { TaxInfoResponse } from "@bitwarden/common/billing/models/response/tax-i
|
||||
import { TaxRateResponse } from "@bitwarden/common/billing/models/response/tax-rate.response";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
||||
import { SharedModule } from "../../shared";
|
||||
|
||||
type TaxInfoView = Omit<TaxInfoResponse, "taxIdType"> & {
|
||||
includeTaxId: boolean;
|
||||
[key: string]: unknown;
|
||||
@@ -17,6 +19,8 @@ type TaxInfoView = Omit<TaxInfoResponse, "taxIdType"> & {
|
||||
@Component({
|
||||
selector: "app-tax-info",
|
||||
templateUrl: "tax-info.component.html",
|
||||
standalone: true,
|
||||
imports: [SharedModule],
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class TaxInfoComponent {
|
||||
@@ -21,13 +21,11 @@ import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/p
|
||||
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
|
||||
import { PolicyListService } from "../admin-console/core/policy-list.service";
|
||||
import { HtmlStorageService } from "../core/html-storage.service";
|
||||
import { I18nService } from "../core/i18n.service";
|
||||
import { CollectionAdminService } from "../vault/core/collection-admin.service";
|
||||
import { PasswordRepromptService } from "../vault/core/password-reprompt.service";
|
||||
|
||||
import { BroadcasterMessagingService } from "./broadcaster-messaging.service";
|
||||
import { EventService } from "./event.service";
|
||||
@@ -87,10 +85,6 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
|
||||
provide: BaseStateServiceAbstraction,
|
||||
useExisting: StateService,
|
||||
},
|
||||
{
|
||||
provide: PasswordRepromptServiceAbstraction,
|
||||
useClass: PasswordRepromptService,
|
||||
},
|
||||
{
|
||||
provide: FileDownloadService,
|
||||
useClass: WebFileDownloadService,
|
||||
|
||||
@@ -47,9 +47,10 @@ export class ProductSwitcherContentComponent {
|
||||
map(([orgs, paramMap]) => {
|
||||
const routeOrg = orgs.find((o) => o.id === paramMap.get("organizationId"));
|
||||
// If the active route org doesn't have access to SM, find the first org that does.
|
||||
const smOrg = routeOrg?.canAccessSecretsManager
|
||||
? routeOrg
|
||||
: orgs.find((o) => o.canAccessSecretsManager);
|
||||
const smOrg =
|
||||
routeOrg?.canAccessSecretsManager && routeOrg?.enabled == true
|
||||
? routeOrg
|
||||
: orgs.find((o) => o.canAccessSecretsManager && o.enabled == true);
|
||||
|
||||
/**
|
||||
* We can update this to the "satisfies" type upon upgrading to TypeScript 4.9
|
||||
|
||||
@@ -131,5 +131,5 @@ OrgWithoutSecretsManager.args = {
|
||||
|
||||
export const OrgWithSecretsManager = Template.bind({});
|
||||
OrgWithSecretsManager.args = {
|
||||
mockOrgs: [{ id: "b", canAccessSecretsManager: true }],
|
||||
mockOrgs: [{ id: "b", canAccessSecretsManager: true, enabled: true }],
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
import { canAccessFeature } from "@bitwarden/angular/guard/feature-flag.guard";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
|
||||
import { SubscriptionRoutingModule } from "../app/billing/settings/subscription-routing.module";
|
||||
import { flagEnabled, Flags } from "../utils/flags";
|
||||
|
||||
import { AcceptFamilySponsorshipComponent } from "./admin-console/organizations/sponsorships/accept-family-sponsorship.component";
|
||||
@@ -223,7 +222,10 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: "subscription",
|
||||
loadChildren: () => SubscriptionRoutingModule,
|
||||
loadChildren: () =>
|
||||
import("./billing/individual/individual-billing.module").then(
|
||||
(m) => m.IndividualBillingModule
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "emergency-access",
|
||||
@@ -254,11 +256,13 @@ const routes: Routes = [
|
||||
children: [
|
||||
{ path: "", pathMatch: "full", redirectTo: "generator" },
|
||||
{
|
||||
path: "",
|
||||
path: "import",
|
||||
loadChildren: () => import("./tools/import/import.module").then((m) => m.ImportModule),
|
||||
},
|
||||
{
|
||||
path: "export",
|
||||
loadChildren: () =>
|
||||
import("./tools/import-export/import-export.module").then(
|
||||
(m) => m.ImportExportModule
|
||||
),
|
||||
import("./tools/vault-export/export.module").then((m) => m.ExportModule),
|
||||
},
|
||||
{
|
||||
path: "generator",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { OrganizationCreateModule } from "./admin-console/organizations/create/organization-create.module";
|
||||
import { OrganizationUserModule } from "./admin-console/organizations/users/organization-user.module";
|
||||
import { AuthModule } from "./auth";
|
||||
import { LoginModule } from "./auth/login/login.module";
|
||||
@@ -17,7 +16,6 @@ import { VaultFilterModule } from "./vault/individual-vault/vault-filter/vault-f
|
||||
VaultFilterModule,
|
||||
OrganizationBadgeModule,
|
||||
OrganizationUserModule,
|
||||
OrganizationCreateModule,
|
||||
LoginModule,
|
||||
AuthModule,
|
||||
],
|
||||
|
||||
@@ -3,9 +3,9 @@ import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { AddEditComponent } from "../../vault/individual-vault/add-edit.component";
|
||||
import { AddEditComponent as OrgAddEditComponent } from "../../vault/org-vault/add-edit.component";
|
||||
|
||||
@@ -4,9 +4,9 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { CipherReportComponent } from "./cipher-report.component";
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { CipherReportComponent } from "./cipher-report.component";
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { CipherReportComponent } from "./cipher-report.component";
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { CipherReportComponent } from "./cipher-report.component";
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { BadgeTypes } from "@bitwarden/components";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
import { CipherReportComponent } from "./cipher-report.component";
|
||||
|
||||
|
||||
@@ -3,12 +3,10 @@ import { NgModule } from "@angular/core";
|
||||
import { PasswordCalloutComponent } from "@bitwarden/auth";
|
||||
|
||||
import { OrganizationSwitcherComponent } from "../admin-console/components/organization-switcher.component";
|
||||
import { OrganizationCreateModule } from "../admin-console/organizations/create/organization-create.module";
|
||||
import { OrganizationLayoutComponent } from "../admin-console/organizations/layouts/organization-layout.component";
|
||||
import { EventsComponent as OrgEventsComponent } from "../admin-console/organizations/manage/events.component";
|
||||
import { UserConfirmComponent as OrgUserConfirmComponent } from "../admin-console/organizations/manage/user-confirm.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 { ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent } from "../admin-console/organizations/tools/exposed-passwords-report.component";
|
||||
import { InactiveTwoFactorReportComponent as OrgInactiveTwoFactorReportComponent } from "../admin-console/organizations/tools/inactive-two-factor-report.component";
|
||||
import { ReusedPasswordsReportComponent as OrgReusedPasswordsReportComponent } from "../admin-console/organizations/tools/reused-passwords-report.component";
|
||||
@@ -16,7 +14,6 @@ import { ToolsComponent as OrgToolsComponent } from "../admin-console/organizati
|
||||
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 { CreateOrganizationComponent } from "../admin-console/settings/create-organization.component";
|
||||
import { SponsoredFamiliesComponent } from "../admin-console/settings/sponsored-families.component";
|
||||
import { SponsoringOrgRowComponent } from "../admin-console/settings/sponsoring-org-row.component";
|
||||
import { AuthModule } from "../auth";
|
||||
@@ -53,19 +50,6 @@ import { UpdatePasswordComponent } from "../auth/update-password.component";
|
||||
import { UpdateTempPasswordComponent } from "../auth/update-temp-password.component";
|
||||
import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component";
|
||||
import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component";
|
||||
import { SecretsManagerBillingModule } from "../billing/organizations/secrets-manager/sm-billing.module";
|
||||
import { AddCreditComponent } from "../billing/settings/add-credit.component";
|
||||
import { AdjustPaymentComponent } from "../billing/settings/adjust-payment.component";
|
||||
import { BillingHistoryViewComponent } from "../billing/settings/billing-history-view.component";
|
||||
import { BillingHistoryComponent } from "../billing/settings/billing-history.component";
|
||||
import { BillingSyncKeyComponent } from "../billing/settings/billing-sync-key.component";
|
||||
import { OrganizationPlansComponent } from "../billing/settings/organization-plans.component";
|
||||
import { PaymentMethodComponent } from "../billing/settings/payment-method.component";
|
||||
import { PaymentComponent } from "../billing/settings/payment.component";
|
||||
import { PremiumComponent } from "../billing/settings/premium.component";
|
||||
import { SubscriptionComponent } from "../billing/settings/subscription.component";
|
||||
import { TaxInfoComponent } from "../billing/settings/tax-info.component";
|
||||
import { UserSubscriptionComponent } from "../billing/settings/user-subscription.component";
|
||||
import { DynamicAvatarComponent } from "../components/dynamic-avatar.component";
|
||||
import { SelectableAvatarComponent } from "../components/selectable-avatar.component";
|
||||
import { FooterComponent } from "../layouts/footer.component";
|
||||
@@ -74,7 +58,6 @@ import { NavbarComponent } from "../layouts/navbar.component";
|
||||
import { ProductSwitcherModule } from "../layouts/product-switcher/product-switcher.module";
|
||||
import { UserLayoutComponent } from "../layouts/user-layout.component";
|
||||
import { AccountComponent } from "../settings/account.component";
|
||||
import { AdjustStorageComponent } from "../settings/adjust-storage.component";
|
||||
import { ApiKeyComponent } from "../settings/api-key.component";
|
||||
import { ChangeAvatarComponent } from "../settings/change-avatar.component";
|
||||
import { ChangeEmailComponent } from "../settings/change-email.component";
|
||||
@@ -88,14 +71,12 @@ import { PurgeVaultComponent } from "../settings/purge-vault.component";
|
||||
import { SecurityKeysComponent } from "../settings/security-keys.component";
|
||||
import { SecurityComponent } from "../settings/security.component";
|
||||
import { SettingsComponent } from "../settings/settings.component";
|
||||
import { UpdateLicenseComponent } from "../settings/update-license.component";
|
||||
import { VaultTimeoutInputComponent } from "../settings/vault-timeout-input.component";
|
||||
import { GeneratorComponent } from "../tools/generator.component";
|
||||
import { PasswordGeneratorHistoryComponent } from "../tools/password-generator-history.component";
|
||||
import { AccessComponent } from "../tools/send/access.component";
|
||||
import { AddEditComponent as SendAddEditComponent } from "../tools/send/add-edit.component";
|
||||
import { ToolsComponent } from "../tools/tools.component";
|
||||
import { PasswordRepromptComponent } from "../vault/components/password-reprompt.component";
|
||||
import { PremiumBadgeComponent } from "../vault/components/premium-badge.component";
|
||||
import { AddEditCustomFieldsComponent } from "../vault/individual-vault/add-edit-custom-fields.component";
|
||||
import { AddEditComponent } from "../vault/individual-vault/add-edit.component";
|
||||
@@ -116,7 +97,6 @@ import { SharedModule } from "./shared.module";
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
OrganizationCreateModule,
|
||||
RegisterFormModule,
|
||||
ProductSwitcherModule,
|
||||
UserVerificationModule,
|
||||
@@ -128,9 +108,6 @@ import { SharedModule } from "./shared.module";
|
||||
AuthModule,
|
||||
EnvironmentSelectorModule,
|
||||
AccountFingerprintComponent,
|
||||
|
||||
// To be removed when OrganizationPlansComponent is moved to its own module (see AC-1453)
|
||||
SecretsManagerBillingModule,
|
||||
PasswordCalloutComponent,
|
||||
],
|
||||
declarations: [
|
||||
@@ -138,18 +115,13 @@ import { SharedModule } from "./shared.module";
|
||||
AcceptOrganizationComponent,
|
||||
AccessComponent,
|
||||
AccountComponent,
|
||||
AddCreditComponent,
|
||||
AddEditComponent,
|
||||
AddEditCustomFieldsComponent,
|
||||
AddEditCustomFieldsComponent,
|
||||
AdjustPaymentComponent,
|
||||
AdjustStorageComponent,
|
||||
ApiKeyComponent,
|
||||
AttachmentsComponent,
|
||||
BillingSyncKeyComponent,
|
||||
ChangeEmailComponent,
|
||||
CollectionsComponent,
|
||||
CreateOrganizationComponent,
|
||||
DeauthorizeSessionsComponent,
|
||||
DeleteAccountComponent,
|
||||
DomainRulesComponent,
|
||||
@@ -160,7 +132,6 @@ import { SharedModule } from "./shared.module";
|
||||
EmergencyAccessTakeoverComponent,
|
||||
EmergencyAccessViewComponent,
|
||||
EmergencyAddEditComponent,
|
||||
FamiliesForEnterpriseSetupComponent,
|
||||
FolderAddEditComponent,
|
||||
FooterComponent,
|
||||
FrontendLayoutComponent,
|
||||
@@ -170,7 +141,6 @@ import { SharedModule } from "./shared.module";
|
||||
OrganizationSwitcherComponent,
|
||||
OrgAddEditComponent,
|
||||
OrganizationLayoutComponent,
|
||||
OrganizationPlansComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgCollectionsComponent,
|
||||
OrgEventsComponent,
|
||||
@@ -183,12 +153,8 @@ import { SharedModule } from "./shared.module";
|
||||
OrgWeakPasswordsReportComponent,
|
||||
GeneratorComponent,
|
||||
PasswordGeneratorHistoryComponent,
|
||||
PasswordRepromptComponent,
|
||||
PaymentComponent,
|
||||
PaymentMethodComponent,
|
||||
PreferencesComponent,
|
||||
PremiumBadgeComponent,
|
||||
PremiumComponent,
|
||||
ProfileComponent,
|
||||
ChangeAvatarComponent,
|
||||
ProvidersComponent,
|
||||
@@ -206,8 +172,6 @@ import { SharedModule } from "./shared.module";
|
||||
SponsoredFamiliesComponent,
|
||||
SponsoringOrgRowComponent,
|
||||
SsoComponent,
|
||||
SubscriptionComponent,
|
||||
TaxInfoComponent,
|
||||
ToolsComponent,
|
||||
TwoFactorAuthenticatorComponent,
|
||||
TwoFactorComponent,
|
||||
@@ -219,13 +183,9 @@ import { SharedModule } from "./shared.module";
|
||||
TwoFactorVerifyComponent,
|
||||
TwoFactorWebAuthnComponent,
|
||||
TwoFactorYubiKeyComponent,
|
||||
UpdateLicenseComponent,
|
||||
UpdatePasswordComponent,
|
||||
UpdateTempPasswordComponent,
|
||||
BillingHistoryComponent,
|
||||
BillingHistoryViewComponent,
|
||||
UserLayoutComponent,
|
||||
UserSubscriptionComponent,
|
||||
VaultTimeoutInputComponent,
|
||||
VerifyEmailComponent,
|
||||
VerifyEmailTokenComponent,
|
||||
@@ -238,17 +198,13 @@ import { SharedModule } from "./shared.module";
|
||||
AcceptOrganizationComponent,
|
||||
AccessComponent,
|
||||
AccountComponent,
|
||||
AddCreditComponent,
|
||||
AddEditComponent,
|
||||
AddEditCustomFieldsComponent,
|
||||
AddEditCustomFieldsComponent,
|
||||
AdjustPaymentComponent,
|
||||
AdjustStorageComponent,
|
||||
ApiKeyComponent,
|
||||
AttachmentsComponent,
|
||||
ChangeEmailComponent,
|
||||
CollectionsComponent,
|
||||
CreateOrganizationComponent,
|
||||
DeauthorizeSessionsComponent,
|
||||
DeleteAccountComponent,
|
||||
DomainRulesComponent,
|
||||
@@ -260,7 +216,6 @@ import { SharedModule } from "./shared.module";
|
||||
EmergencyAccessTakeoverComponent,
|
||||
EmergencyAccessViewComponent,
|
||||
EmergencyAddEditComponent,
|
||||
FamiliesForEnterpriseSetupComponent,
|
||||
FolderAddEditComponent,
|
||||
FooterComponent,
|
||||
FrontendLayoutComponent,
|
||||
@@ -270,7 +225,6 @@ import { SharedModule } from "./shared.module";
|
||||
OrganizationSwitcherComponent,
|
||||
OrgAddEditComponent,
|
||||
OrganizationLayoutComponent,
|
||||
OrganizationPlansComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgCollectionsComponent,
|
||||
OrgEventsComponent,
|
||||
@@ -283,12 +237,8 @@ import { SharedModule } from "./shared.module";
|
||||
OrgWeakPasswordsReportComponent,
|
||||
GeneratorComponent,
|
||||
PasswordGeneratorHistoryComponent,
|
||||
PasswordRepromptComponent,
|
||||
PaymentComponent,
|
||||
PaymentMethodComponent,
|
||||
PreferencesComponent,
|
||||
PremiumBadgeComponent,
|
||||
PremiumComponent,
|
||||
ProfileComponent,
|
||||
ChangeAvatarComponent,
|
||||
ProvidersComponent,
|
||||
@@ -306,8 +256,6 @@ import { SharedModule } from "./shared.module";
|
||||
SponsoredFamiliesComponent,
|
||||
SponsoringOrgRowComponent,
|
||||
SsoComponent,
|
||||
SubscriptionComponent,
|
||||
TaxInfoComponent,
|
||||
ToolsComponent,
|
||||
TwoFactorAuthenticatorComponent,
|
||||
TwoFactorComponent,
|
||||
@@ -319,13 +267,9 @@ import { SharedModule } from "./shared.module";
|
||||
TwoFactorVerifyComponent,
|
||||
TwoFactorWebAuthnComponent,
|
||||
TwoFactorYubiKeyComponent,
|
||||
UpdateLicenseComponent,
|
||||
UpdatePasswordComponent,
|
||||
UpdateTempPasswordComponent,
|
||||
BillingHistoryComponent,
|
||||
BillingHistoryViewComponent,
|
||||
UserLayoutComponent,
|
||||
UserSubscriptionComponent,
|
||||
VaultTimeoutInputComponent,
|
||||
VerifyEmailComponent,
|
||||
VerifyEmailTokenComponent,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user