From c761cebc1b028bf8d837020ffcb3b180a4b78c82 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Wed, 6 Mar 2024 04:53:41 +0100 Subject: [PATCH 1/7] update web-vault to v2024.2.4 --- Dockerfile | 4 +- patches/v2024.2.4.patch | 732 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 734 insertions(+), 2 deletions(-) create mode 100644 patches/v2024.2.4.patch diff --git a/Dockerfile b/Dockerfile index bdbcc53..9249dc5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,8 @@ USER node # Can be a tag, release, but prefer a commit hash because it's not changeable # https://github.com/bitwarden/clients/commit/${VAULT_VERSION} # -# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.1.2 -ARG VAULT_VERSION=a1a5c4b3d3c5787e9517ac30b9b6f344f18fe5e6 +# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.2.4 +ARG VAULT_VERSION=6d90d5aff28f960406845e86aa4a5d11244395ad WORKDIR /vault RUN git -c init.defaultBranch=main init && \ diff --git a/patches/v2024.2.4.patch b/patches/v2024.2.4.patch new file mode 100644 index 0000000..72f6fd8 --- /dev/null +++ b/patches/v2024.2.4.patch @@ -0,0 +1,732 @@ +diff --git a/apps/web/src/app/admin-console/icons/admin-console-logo.ts b/apps/web/src/app/admin-console/icons/admin-console-logo.ts +index 32b2b7a13a..1f1e6827bf 100644 +--- a/apps/web/src/app/admin-console/icons/admin-console-logo.ts ++++ b/apps/web/src/app/admin-console/icons/admin-console-logo.ts +@@ -1,5 +1,11 @@ + import { svgIcon } from "@bitwarden/components"; + + export const AdminConsoleLogo = svgIcon` +- ++ ++ ++ ++ ++ ++ ++ + `; +diff --git a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html +index 6029cfd833..04324b7d19 100644 +--- a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html ++++ b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html +@@ -12,7 +12,7 @@ + + + +- {{ "billingEmail" | i18n }} ++ {{ "email" | i18n }} + + + +diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +index 7e50a09087..27ea8f09c9 100644 +--- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts ++++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +@@ -105,6 +105,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { + } + + canShowBillingTab(organization: Organization): boolean { ++ return false; // disable billing tab in Vaultwarden + return canAccessBillingTab(organization); + } + +diff --git a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts +index 7abee6b0d0..2e3b789b23 100644 +--- a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts ++++ b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts +@@ -68,13 +68,6 @@ const routes: Routes = [ + (m) => m.OrganizationReportingModule, + ), + }, +- { +- path: "billing", +- loadChildren: () => +- import("../../billing/organizations/organization-billing.module").then( +- (m) => m.OrganizationBillingModule, +- ), +- }, + ], + }, + ]; +diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html +index 7035b976ca..44b24584ae 100644 +--- a/apps/web/src/app/admin-console/organizations/settings/account.component.html ++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html +@@ -17,7 +17,7 @@ + + + +- {{ "billingEmail" | i18n }} ++ {{ "email" | i18n }} + + + +diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts +index 8527aa1b17..971d78d8d5 100644 +--- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts ++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts +@@ -99,7 +99,7 @@ export class AccountComponent { + ) {} + + async ngOnInit() { +- this.selfHosted = this.platformUtilsService.isSelfHost(); ++ this.selfHosted = false; // set to false so we can rename organizations + + this.route.params + .pipe( +@@ -204,6 +204,7 @@ export class AccountComponent { + } + + submitCollectionManagement = async () => { ++ return; // flexible collections are not supported by Vaultwarden + // Early exit if self-hosted + if (this.selfHosted) { + return; +diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts +index f9479a92ce..9a6c489c38 100644 +--- a/apps/web/src/app/app.component.ts ++++ b/apps/web/src/app/app.component.ts +@@ -205,6 +205,10 @@ export class AppComponent implements OnDestroy, OnInit { + break; + } + case "showToast": ++ if (typeof message.text === "string" && typeof crypto.subtle === "undefined") { ++ message.title = "This browser requires HTTPS to use the web vault"; ++ message.text = "Check the Vaultwarden wiki for details on how to enable it"; ++ } + this.showToast(message); + break; + case "convertAccountToKeyConnector": +diff --git a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html +index 4690a4e63a..9d297671d2 100644 +--- a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html ++++ b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html +@@ -1,6 +1,6 @@ +
+
+- ++ +

+ +

+- ++ +

+ {{ "loginOrCreateNewAccount" | i18n }} +

+@@ -51,7 +51,7 @@ + +
+ +-
++
+

{{ "or" | i18n }}

+ + + +- +- +diff --git a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts +index 849e003440..de32156aad 100644 +--- a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts ++++ b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts +@@ -109,11 +109,11 @@ export class TwoFactorAuthenticatorComponent + new window.QRious({ + element: document.getElementById("qr"), + value: +- "otpauth://totp/Bitwarden:" + ++ "otpauth://totp/Vaultwarden:" + + Utils.encodeRFC3986URIComponent(email) + + "?secret=" + + encodeURIComponent(this.key) + +- "&issuer=Bitwarden", ++ "&issuer=Vaultwarden", + size: 160, + }); + }, 100); +diff --git a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts +index 78872aa6a9..eed953b91a 100644 +--- a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts ++++ b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts +@@ -44,7 +44,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy { + return; + } + this.loading = true; +- this.billing = await this.organizationApiService.getBilling(this.organizationId); ++ this.billing = null; + this.loading = false; + } + } +diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html +index a77d42a359..7de4e33fe2 100644 +--- a/apps/web/src/app/billing/organizations/organization-plans.component.html ++++ b/apps/web/src/app/billing/organizations/organization-plans.component.html +@@ -6,7 +6,7 @@ + >
+ {{ "loading" | i18n }} + +- ++ +

{{ "uploadLicenseFileOrg" | i18n }}

+
+
+@@ -28,7 +28,7 @@ + (ngSubmit)="submit()" + [appApiAction]="formPromise" + ngNativeValidate +- *ngIf="!loading && !selfHosted && this.passwordManagerPlans && this.secretsManagerPlans" ++ *ngIf="!loading" + class="tw-pt-6" + > + !!plan.PasswordManager); +@@ -186,6 +187,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + this.plan = providerDefaultPlan.type; + this.product = providerDefaultPlan.product; + } ++ end of asking /api/plans in Vaultwarden */ + + if (!this.createOrganization) { + this.upgradeFlowPrefillForm(); +@@ -257,6 +259,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get selectableProducts() { ++ return null; // there are no products to select in Vaultwarden + if (this.acceptingSponsorship) { + const familyPlan = this.passwordManagerPlans.find( + (plan) => plan.type === PlanType.FamiliesAnnually, +@@ -287,6 +290,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get selectablePlans() { ++ return null; // no plans to select in Vaultwarden + const selectedProductType = this.formGroup.controls.product.value; + const result = + this.passwordManagerPlans?.filter( +@@ -427,10 +431,12 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get planOffersSecretsManager() { ++ return false; // no support for secrets manager in Vaultwarden + return this.selectedSecretsManagerPlan != null; + } + + changedProduct() { ++ return; // no choice of products in Vaultwarden + const selectedPlan = this.selectablePlans[0]; + + this.setPlanType(selectedPlan.type); +@@ -543,7 +549,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + const orgKeys = await this.cryptoService.makeKeyPair(orgKey[1]); + + if (this.selfHosted) { +- orgId = await this.createSelfHosted(key, collectionCt, orgKeys); ++ orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]); + } else { + orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]); + } +@@ -643,7 +649,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + request.name = this.formGroup.controls.name.value; + request.billingEmail = this.formGroup.controls.billingEmail.value; + request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString); ++ request.planType = PlanType.Free; // always select the free plan in Vaultwarden + ++ /* there is no plan to select in Vaultwarden + if (this.selectedPlan.type === PlanType.Free) { + request.planType = PlanType.Free; + } else { +@@ -673,6 +681,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + + // Secrets Manager + this.buildSecretsManagerRequest(request); ++ end plan selection and no support for secret manager in Vaultwarden */ + + if (this.hasProvider) { + const providerRequest = new ProviderOrganizationCreateRequest( +@@ -754,6 +763,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + private upgradeFlowPrefillForm() { ++ return; // Vaultwarden only supports free plan + if (this.acceptingSponsorship) { + this.formGroup.controls.product.setValue(ProductType.Families); + this.changedProduct(); +diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts +index 899a168479..5bb71b05f6 100644 +--- a/apps/web/src/app/core/init.service.ts ++++ b/apps/web/src/app/core/init.service.ts +@@ -7,10 +7,7 @@ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwar + import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; + import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service"; + import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; +-import { +- EnvironmentService as EnvironmentServiceAbstraction, +- Urls, +-} from "@bitwarden/common/platform/abstractions/environment.service"; ++import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/platform/abstractions/environment.service"; + import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; + import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; + import { ConfigService } from "@bitwarden/common/platform/services/config/config.service"; +@@ -38,11 +35,23 @@ export class InitService { + ) {} + + init() { ++ function getBaseUrl() { ++ // If the base URL is `https://vaultwarden.example.com/base/path/`, ++ // `window.location.href` should have one of the following forms: ++ // ++ // - `https://vaultwarden.example.com/base/path/` ++ // - `https://vaultwarden.example.com/base/path/#/some/route[?queryParam=...]` ++ // ++ // We want to get to just `https://vaultwarden.example.com/base/path`. ++ let baseUrl = window.location.href; ++ baseUrl = baseUrl.replace(/#.*/, ""); // Strip off `#` and everything after. ++ baseUrl = baseUrl.replace(/\/+$/, ""); // Trim any trailing `/` chars. ++ return baseUrl; ++ } + return async () => { + await this.stateService.init(); + +- const urls = process.env.URLS as Urls; +- urls.base ??= this.win.location.origin; ++ const urls = { base: getBaseUrl() }; + await this.environmentService.setUrls(urls); + // Workaround to ignore stateService.activeAccount until process.env.URLS are set + // TODO: Remove this when implementing ticket PM-2637 +diff --git a/apps/web/src/app/core/router.service.ts b/apps/web/src/app/core/router.service.ts +index 5a0d903ba7..d6fedadd38 100644 +--- a/apps/web/src/app/core/router.service.ts ++++ b/apps/web/src/app/core/router.service.ts +@@ -26,7 +26,7 @@ export class RouterService { + .subscribe((event: NavigationEnd) => { + this.currentUrl = event.url; + +- let title = i18nService.t("bitWebVault"); ++ let title = "Vaultwarden Web"; + + if (this.currentUrl.includes("/sm/")) { + title = i18nService.t("bitSecretsManager"); +diff --git a/apps/web/src/app/core/web-platform-utils.service.ts b/apps/web/src/app/core/web-platform-utils.service.ts +index 02c7c29e34..9fd100024a 100644 +--- a/apps/web/src/app/core/web-platform-utils.service.ts ++++ b/apps/web/src/app/core/web-platform-utils.service.ts +@@ -133,14 +133,17 @@ export class WebPlatformUtilsService implements PlatformUtilsService { + } + + isDev(): boolean { ++ return false; // treat Vaultwarden as production ready + return process.env.NODE_ENV === "development"; + } + + isSelfHost(): boolean { ++ return true; // treat Vaultwarden as self hosted + return WebPlatformUtilsService.isSelfHost(); + } + + static isSelfHost(): boolean { ++ return true; // treat Vaultwarden as self hosted + return process.env.ENV.toString() === "selfhosted"; + } + +diff --git a/apps/web/src/app/layouts/frontend-layout.component.html b/apps/web/src/app/layouts/frontend-layout.component.html +index 72f0f1f1da..cea0867131 100644 +--- a/apps/web/src/app/layouts/frontend-layout.component.html ++++ b/apps/web/src/app/layouts/frontend-layout.component.html +@@ -1,6 +1,11 @@ + +
+- +- © {{ year }} Bitwarden Inc.
++ Vaultwarden Web
+ {{ "versionNumber" | i18n: version }} ++

++
++ A modified version of the Bitwarden® Web Vault for Vaultwarden (an unofficial rewrite of the ++ Bitwarden® server).
++ Vaultwarden is not associated with the Bitwarden® project nor Bitwarden Inc. ++
+
+diff --git a/apps/web/src/app/layouts/header/web-header.component.html b/apps/web/src/app/layouts/header/web-header.component.html +index 514e5deebd..20165e5061 100644 +--- a/apps/web/src/app/layouts/header/web-header.component.html ++++ b/apps/web/src/app/layouts/header/web-header.component.html +@@ -76,7 +76,12 @@ + + {{ "accountSettings" | i18n }} +
+- ++ + + {{ "getHelp" | i18n }} + +diff --git a/apps/web/src/app/layouts/password-manager-logo.ts b/apps/web/src/app/layouts/password-manager-logo.ts +index d93e2d5bb3..e15394f785 100644 +--- a/apps/web/src/app/layouts/password-manager-logo.ts ++++ b/apps/web/src/app/layouts/password-manager-logo.ts +@@ -1,5 +1,11 @@ + import { svgIcon } from "@bitwarden/components"; + + export const PasswordManagerLogo = svgIcon` +- ++ ++ ++ ++ ++ ++ ++ + `; +diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html +index 9068f9c071..e051dccc85 100644 +--- a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html ++++ b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html +@@ -29,7 +29,7 @@ + + +
+ {{ "moreFromBitwarden" | i18n }} +diff --git a/apps/web/src/app/layouts/user-layout.component.html b/apps/web/src/app/layouts/user-layout.component.html +index 3593390113..ac78bcb651 100644 +--- a/apps/web/src/app/layouts/user-layout.component.html ++++ b/apps/web/src/app/layouts/user-layout.component.html +@@ -33,9 +33,5 @@ + > + + +- + + +diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts +index e5c2f353c0..845d8b86ab 100644 +--- a/apps/web/src/app/oss-routing.module.ts ++++ b/apps/web/src/app/oss-routing.module.ts +@@ -222,13 +222,6 @@ const routes: Routes = [ + component: DomainRulesComponent, + data: { titleId: "domainRules" }, + }, +- { +- path: "subscription", +- loadChildren: () => +- import("./billing/individual/individual-billing.module").then( +- (m) => m.IndividualBillingModule, +- ), +- }, + { + path: "emergency-access", + children: [ +diff --git a/apps/web/src/app/settings/settings.component.ts b/apps/web/src/app/settings/settings.component.ts +index c2fd1c77fa..9e116d7f2c 100644 +--- a/apps/web/src/app/settings/settings.component.ts ++++ b/apps/web/src/app/settings/settings.component.ts +@@ -53,14 +53,7 @@ export class SettingsComponent implements OnInit, OnDestroy { + } + + async load() { +- this.premium = await this.stateService.getHasPremiumPersonally(); +- this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships(); +- const hasPremiumFromOrg = await this.stateService.getHasPremiumFromOrganization(); +- let billing = null; +- if (!this.selfHosted) { +- billing = await this.apiService.getUserBillingHistory(); +- } +- this.hideSubscription = +- !this.premium && hasPremiumFromOrg && (this.selfHosted || billing?.hasNoHistory); ++ this.hasFamilySponsorshipAvailable = false; // disable family Sponsorships in Vaultwarden ++ this.hideSubscription = true; // always hide subscriptions in Vaultwarden + } + } +diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts +index 770a862eab..863efc8769 100644 +--- a/apps/web/src/app/shared/loose-components.module.ts ++++ b/apps/web/src/app/shared/loose-components.module.ts +@@ -59,7 +59,6 @@ import { UpdateTempPasswordComponent } from "../auth/update-temp-password.compon + import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component"; + import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component"; + import { DynamicAvatarComponent } from "../components/dynamic-avatar.component"; +-import { PaymentMethodBannersComponent } from "../components/payment-method-banners/payment-method-banners.component"; + import { SelectableAvatarComponent } from "../components/selectable-avatar.component"; + import { FrontendLayoutComponent } from "../layouts/frontend-layout.component"; + import { HeaderModule } from "../layouts/header/header.module"; +@@ -106,7 +105,6 @@ import { SharedModule } from "./shared.module"; + PipesModule, + PasswordCalloutComponent, + DangerZoneComponent, +- PaymentMethodBannersComponent, + LayoutComponent, + NavigationModule, + HeaderModule, +diff --git a/apps/web/src/app/tools/send/access.component.html b/apps/web/src/app/tools/send/access.component.html +index 6fef7d361d..1deb1164ff 100644 +--- a/apps/web/src/app/tools/send/access.component.html ++++ b/apps/web/src/app/tools/send/access.component.html +@@ -2,7 +2,7 @@ +
+- ++ +
+

View Send

+
+@@ -66,19 +66,6 @@ +
+

+ {{ "sendAccessTaglineProductDesc" | i18n }} +- {{ "sendAccessTaglineLearnMore" | i18n }} +- Bitwarden Send +- {{ "sendAccessTaglineOr" | i18n }} +- {{ +- "sendAccessTaglineSignUp" | i18n +- }} +- {{ "sendAccessTaglineTryToday" | i18n }} +

+
+
+diff --git a/apps/web/src/index.html b/apps/web/src/index.html +index c3a2c03ed9..1a326771a6 100644 +--- a/apps/web/src/index.html ++++ b/apps/web/src/index.html +@@ -5,7 +5,7 @@ + + + +- Bitwarden Web Vault ++ Vaultwarden Web + + + +@@ -17,7 +17,7 @@ + +
+
+- ++ +

+ form:nth-child(1) > div:nth-child(3) { ++ @extend %vw-hide; ++} ++ ++/* Hide the `This account is owned by a business` checkbox and label */ ++#ownedBusiness, ++label[for^="ownedBusiness"] { ++ @extend %vw-hide; ++} ++ ++/* Hide the radio button and label for the `Custom` org user type */ ++#userTypeCustom, ++label[for^="userTypeCustom"] { ++ @extend %vw-hide; ++} ++ ++/* Hide Business Name */ ++app-org-account form div bit-form-field.tw-block:nth-child(3) { ++ @extend %vw-hide; ++} ++ ++/* Hide organization plans */ ++app-organization-plans > form > h2.mt-5 { ++ @extend %vw-hide; ++} ++ ++/* Hide Device Verification form at the Two Step Login screen */ ++app-security > app-two-factor-setup > form { ++ @extend %vw-hide; ++} ++ ++/* Replace the Bitwarden Shield at the top left with a Vaultwarden icon */ ++.bwi-shield:before { ++ content: "" !important; ++ width: 32px !important; ++ height: 40px !important; ++ display: block !important; ++ background-image: url(../images/icon-white.png) !important; ++ background-repeat: no-repeat; ++ background-position-y: bottom; ++} ++/**** END Vaultwarden CHANGES ****/ +diff --git a/apps/web/src/scss/variables.scss b/apps/web/src/scss/variables.scss +index 9d3d8d6ad4..5bc773c0d8 100644 +--- a/apps/web/src/scss/variables.scss ++++ b/apps/web/src/scss/variables.scss +@@ -3,7 +3,7 @@ $dark-icon-themes: "theme_dark"; + $primary: #175ddc; + $primary-accent: #1252a3; + $secondary: #ced4da; +-$secondary-alt: #1a3b66; ++$secondary-alt: #212529; + $success: #017e45; + $info: #555555; + $warning: #8b6609; +diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js +index 6ac384cb82..0492e09476 100644 +--- a/apps/web/webpack.config.js ++++ b/apps/web/webpack.config.js +@@ -141,8 +141,6 @@ const plugins = [ + { from: "./src/favicon.ico" }, + { from: "./src/browserconfig.xml" }, + { from: "./src/app-id.json" }, +- { from: "./src/404.html" }, +- { from: "./src/404", to: "404" }, + { from: "./src/images", to: "images" }, + { from: "./src/locales", to: "locales" }, + { from: "../../node_modules/qrious/dist/qrious.min.js", to: "scripts" }, +diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts +index 3cffebe71b..c1229b5c2c 100644 +--- a/libs/angular/src/auth/components/register.component.ts ++++ b/libs/angular/src/auth/components/register.component.ts +@@ -106,6 +106,14 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn + } + + async submit(showToast = true) { ++ if (typeof crypto.subtle === "undefined") { ++ this.platformUtilsService.showToast( ++ "error", ++ "This browser requires HTTPS to use the web vault", ++ "Check the Vaultwarden wiki for details on how to enable it", ++ ); ++ return; ++ } + let email = this.formGroup.value.email; + email = email.trim().toLowerCase(); + let name = this.formGroup.value.name; +diff --git a/libs/angular/src/auth/components/two-factor-options.component.ts b/libs/angular/src/auth/components/two-factor-options.component.ts +index 4293eb9966..7a8e861e8d 100644 +--- a/libs/angular/src/auth/components/two-factor-options.component.ts ++++ b/libs/angular/src/auth/components/two-factor-options.component.ts +@@ -30,7 +30,9 @@ export class TwoFactorOptionsComponent implements OnInit { + } + + recover() { +- this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/recover-2fa"); ++ this.platformUtilsService.launchUri( ++ "https://bitwarden.com/help/two-step-recovery-code/#use-your-recovery-code", ++ ); + this.onRecoverSelected.emit(); + } + } From 8544453a5e2c1f6c0c11a686812677dceab6732f Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Thu, 7 Mar 2024 00:23:06 +0100 Subject: [PATCH 2/7] update web-vault to v2024.2.5 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9249dc5..3db8185 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,8 @@ USER node # Can be a tag, release, but prefer a commit hash because it's not changeable # https://github.com/bitwarden/clients/commit/${VAULT_VERSION} # -# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.2.4 -ARG VAULT_VERSION=6d90d5aff28f960406845e86aa4a5d11244395ad +# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.2.5 +ARG VAULT_VERSION=467d94774eb9eb37c31da4837aab82a24f38b01e WORKDIR /vault RUN git -c init.defaultBranch=main init && \ From 3f796d050317b837cc1d36fd752acc740fbc8463 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 9 Mar 2024 07:33:05 +0100 Subject: [PATCH 3/7] change light mode color scheme --- patches/v2024.2.4.patch | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/patches/v2024.2.4.patch b/patches/v2024.2.4.patch index 72f6fd8..34327bf 100644 --- a/patches/v2024.2.4.patch +++ b/patches/v2024.2.4.patch @@ -730,3 +730,25 @@ index 4293eb9966..7a8e861e8d 100644 this.onRecoverSelected.emit(); } } +diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css +index 75a8fa6380..733dbe9413 100644 +--- a/libs/components/src/tw-theme.css ++++ b/libs/components/src/tw-theme.css +@@ -6,12 +6,12 @@ + --color-background: 255 255 255; + --color-background-alt: 251 251 251; + --color-background-alt2: 23 92 219; +- --color-background-alt3: 18 82 163; +- --color-background-alt4: 13 60 119; ++ --color-background-alt3: 33 37 41; /* bg of menu panel */ ++ --color-background-alt4: 16 18 21; /* bg of active menu item */ + +- --color-primary-300: 103 149 232; +- --color-primary-500: 23 93 220; +- --color-primary-700: 18 82 163; ++ --color-primary-300: 108 117 125; /* hover of menu items */ ++ --color-primary-500: 18 82 163; /* color of links and buttons */ ++ --color-primary-700: 13 60 119; /* hover of links and buttons */ + + --color-secondary-100: 240 240 240; + --color-secondary-300: 206 212 220; From 21ffad4495863ef65e85efc63dade424bc88154e Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 9 Mar 2024 07:58:25 +0100 Subject: [PATCH 4/7] create script to replace svg icons --- patches/v2024.2.4.patch | 34 ------------------- resources/vaultwarden-admin-console-logo.svg | 7 ++++ .../vaultwarden-password-manager-logo.svg | 7 ++++ scripts/apply_patches.sh | 8 +++++ scripts/generate_patch_file.sh | 2 ++ scripts/replace-embedded-svg-icons.sh | 20 +++++++++++ 6 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 resources/vaultwarden-admin-console-logo.svg create mode 100644 resources/vaultwarden-password-manager-logo.svg create mode 100755 scripts/replace-embedded-svg-icons.sh diff --git a/patches/v2024.2.4.patch b/patches/v2024.2.4.patch index 34327bf..4e7136c 100644 --- a/patches/v2024.2.4.patch +++ b/patches/v2024.2.4.patch @@ -1,20 +1,3 @@ -diff --git a/apps/web/src/app/admin-console/icons/admin-console-logo.ts b/apps/web/src/app/admin-console/icons/admin-console-logo.ts -index 32b2b7a13a..1f1e6827bf 100644 ---- a/apps/web/src/app/admin-console/icons/admin-console-logo.ts -+++ b/apps/web/src/app/admin-console/icons/admin-console-logo.ts -@@ -1,5 +1,11 @@ - import { svgIcon } from "@bitwarden/components"; - - export const AdminConsoleLogo = svgIcon` -- -+ -+ -+ -+ -+ -+ -+ - `; diff --git a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html index 6029cfd833..04324b7d19 100644 --- a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html @@ -407,23 +390,6 @@ index 514e5deebd..20165e5061 100644 {{ "getHelp" | i18n }} -diff --git a/apps/web/src/app/layouts/password-manager-logo.ts b/apps/web/src/app/layouts/password-manager-logo.ts -index d93e2d5bb3..e15394f785 100644 ---- a/apps/web/src/app/layouts/password-manager-logo.ts -+++ b/apps/web/src/app/layouts/password-manager-logo.ts -@@ -1,5 +1,11 @@ - import { svgIcon } from "@bitwarden/components"; - - export const PasswordManagerLogo = svgIcon` -- -+ -+ -+ -+ -+ -+ -+ - `; diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html index 9068f9c071..e051dccc85 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html diff --git a/resources/vaultwarden-admin-console-logo.svg b/resources/vaultwarden-admin-console-logo.svg new file mode 100644 index 0000000..a856cd0 --- /dev/null +++ b/resources/vaultwarden-admin-console-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/vaultwarden-password-manager-logo.svg b/resources/vaultwarden-password-manager-logo.svg new file mode 100644 index 0000000..84faae7 --- /dev/null +++ b/resources/vaultwarden-password-manager-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/scripts/apply_patches.sh b/scripts/apply_patches.sh index a641298..4deaf7b 100755 --- a/scripts/apply_patches.sh +++ b/scripts/apply_patches.sh @@ -29,6 +29,14 @@ fi echo "Patching images" cp -vfR ../resources/src/* ./apps/web/src/ +echo "Patching logos" +../scripts/replace-embedded-svg-icons.sh \ + ../resources/vaultwarden-admin-console-logo.svg \ + ./apps/web/src/app/admin-console/icons/admin-console-logo.ts +../scripts/replace-embedded-svg-icons.sh \ + ../resources/vaultwarden-password-manager-logo.svg \ + ./apps/web/src/app/layouts/password-manager-logo.ts + echo "Using patch: ${PATCH_NAME}" git apply "../patches/${PATCH_NAME}" --reject diff --git a/scripts/generate_patch_file.sh b/scripts/generate_patch_file.sh index 98c8d9b..48cbffa 100755 --- a/scripts/generate_patch_file.sh +++ b/scripts/generate_patch_file.sh @@ -36,6 +36,8 @@ if [ "$(git status --porcelain | wc -l)" -ge 1 ]; then ':!apps/web/src/images/icons/favicon-32x32.png' \ ':!apps/web/src/images/icons/mstile-150x150.png' \ ':!apps/web/src/images/icons/safari-pinned-tab.svg' \ + ':!apps/web/src/app/admin-console/icons/admin-console-logo.ts' \ + ':!apps/web/src/app/layouts/password-manager-logo.ts' \ > "../patches/${PATCH_FILENAME}" echo "Patch has been created here: patches/${PATCH_FILENAME}" else diff --git a/scripts/replace-embedded-svg-icons.sh b/scripts/replace-embedded-svg-icons.sh new file mode 100755 index 0000000..b1cad6d --- /dev/null +++ b/scripts/replace-embedded-svg-icons.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ ! -f $1 ] +then + echo "$1 does not exist" + exit -1 +fi + +if [ ! -f $2 ] +then + echo "$2 does not exist" + exit -1 +fi + +echo "'$1' -> '$2'" + +first='`$' +last='^`' +sed -i "/$first/,/$last/{ /$first/{p; r $1 +}; /$last/p; d }" $2 From 9b23b3686068d41642f0a3e0b5417830141a58b3 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 9 Mar 2024 08:46:13 +0100 Subject: [PATCH 5/7] make it work with docker --- scripts/apply_patches.sh | 16 ++++++++++++++-- scripts/replace-embedded-svg-icons.sh | 20 -------------------- 2 files changed, 14 insertions(+), 22 deletions(-) delete mode 100755 scripts/replace-embedded-svg-icons.sh diff --git a/scripts/apply_patches.sh b/scripts/apply_patches.sh index 4deaf7b..f7c92d3 100755 --- a/scripts/apply_patches.sh +++ b/scripts/apply_patches.sh @@ -1,6 +1,18 @@ #!/usr/bin/env bash set -o pipefail -o errexit +function replace_embedded_svg_icon() { +if [ ! -f $1 ]; then echo "$1 does not exist"; exit -1; fi +if [ ! -f $2 ]; then echo "$2 does not exist"; exit -1; fi + +echo "'$1' -> '$2'" + +first='`$' +last='^`' +sed -i "/$first/,/$last/{ /$first/{p; r $1 +}; /$last/p; d }" $2 +} + # If a patch was not provided, try to choose one if [[ -z ${PATCH_NAME} ]]; then # If a patch with the same name as the ref exists, use it @@ -30,10 +42,10 @@ echo "Patching images" cp -vfR ../resources/src/* ./apps/web/src/ echo "Patching logos" -../scripts/replace-embedded-svg-icons.sh \ +replace_embedded_svg_icon \ ../resources/vaultwarden-admin-console-logo.svg \ ./apps/web/src/app/admin-console/icons/admin-console-logo.ts -../scripts/replace-embedded-svg-icons.sh \ +replace_embedded_svg_icon \ ../resources/vaultwarden-password-manager-logo.svg \ ./apps/web/src/app/layouts/password-manager-logo.ts diff --git a/scripts/replace-embedded-svg-icons.sh b/scripts/replace-embedded-svg-icons.sh deleted file mode 100755 index b1cad6d..0000000 --- a/scripts/replace-embedded-svg-icons.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -if [ ! -f $1 ] -then - echo "$1 does not exist" - exit -1 -fi - -if [ ! -f $2 ] -then - echo "$2 does not exist" - exit -1 -fi - -echo "'$1' -> '$2'" - -first='`$' -last='^`' -sed -i "/$first/,/$last/{ /$first/{p; r $1 -}; /$last/p; d }" $2 From b4b89efdf643c651950d864c7b7795368b7ee854 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 9 Mar 2024 10:35:34 +0100 Subject: [PATCH 6/7] normalize commit id length --- scripts/generate_patch_file.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate_patch_file.sh b/scripts/generate_patch_file.sh index 48cbffa..b62fddd 100755 --- a/scripts/generate_patch_file.sh +++ b/scripts/generate_patch_file.sh @@ -23,7 +23,7 @@ fi PATCH_FILENAME="${VAULT_VERSION}.patch" if [ "$(git status --porcelain | wc -l)" -ge 1 ]; then - git --no-pager diff --no-color --minimal -- . \ + git --no-pager diff --no-color --minimal --abbrev=10 -- . \ ':!package-lock.json' \ ':!apps/web/src/favicon.ico' \ ':!apps/web/src/images/logo-dark@2x.png' \ From a249de3ec1a180b9db4b48dbb5ac0fe3df7adb07 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Thu, 21 Mar 2024 17:51:39 +0100 Subject: [PATCH 7/7] update web-vault to v2024.3.0 --- Dockerfile | 4 +- patches/v2024.3.0.patch | 719 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 721 insertions(+), 2 deletions(-) create mode 100644 patches/v2024.3.0.patch diff --git a/Dockerfile b/Dockerfile index 3db8185..4c110ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,8 @@ USER node # Can be a tag, release, but prefer a commit hash because it's not changeable # https://github.com/bitwarden/clients/commit/${VAULT_VERSION} # -# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.2.5 -ARG VAULT_VERSION=467d94774eb9eb37c31da4837aab82a24f38b01e +# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.3.0 +ARG VAULT_VERSION=dbf0f1e328e73bbdea9f120c020770c9e117ad6d WORKDIR /vault RUN git -c init.defaultBranch=main init && \ diff --git a/patches/v2024.3.0.patch b/patches/v2024.3.0.patch new file mode 100644 index 0000000..dc2e448 --- /dev/null +++ b/patches/v2024.3.0.patch @@ -0,0 +1,719 @@ +diff --git a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html +index 6029cfd833..04324b7d19 100644 +--- a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html ++++ b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html +@@ -12,7 +12,7 @@ + + + +- {{ "billingEmail" | i18n }} ++ {{ "email" | i18n }} + + + +diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +index 90010160aa..4d0a2717af 100644 +--- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts ++++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +@@ -113,6 +113,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { + } + + canShowBillingTab(organization: Organization): boolean { ++ return false; // disable billing tab in Vaultwarden + return canAccessBillingTab(organization); + } + +diff --git a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts +index 7abee6b0d0..2e3b789b23 100644 +--- a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts ++++ b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts +@@ -68,13 +68,6 @@ const routes: Routes = [ + (m) => m.OrganizationReportingModule, + ), + }, +- { +- path: "billing", +- loadChildren: () => +- import("../../billing/organizations/organization-billing.module").then( +- (m) => m.OrganizationBillingModule, +- ), +- }, + ], + }, + ]; +diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html +index 7035b976ca..44b24584ae 100644 +--- a/apps/web/src/app/admin-console/organizations/settings/account.component.html ++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html +@@ -17,7 +17,7 @@ + + + +- {{ "billingEmail" | i18n }} ++ {{ "email" | i18n }} + + + +diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts +index 8527aa1b17..971d78d8d5 100644 +--- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts ++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts +@@ -99,7 +99,7 @@ export class AccountComponent { + ) {} + + async ngOnInit() { +- this.selfHosted = this.platformUtilsService.isSelfHost(); ++ this.selfHosted = false; // set to false so we can rename organizations + + this.route.params + .pipe( +@@ -204,6 +204,7 @@ export class AccountComponent { + } + + submitCollectionManagement = async () => { ++ return; // flexible collections are not supported by Vaultwarden + // Early exit if self-hosted + if (this.selfHosted) { + return; +diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts +index 73721de789..1b1726ff1f 100644 +--- a/apps/web/src/app/app.component.ts ++++ b/apps/web/src/app/app.component.ts +@@ -213,6 +213,10 @@ export class AppComponent implements OnDestroy, OnInit { + break; + } + case "showToast": ++ if (typeof message.text === "string" && typeof crypto.subtle === "undefined") { ++ message.title = "This browser requires HTTPS to use the web vault"; ++ message.text = "Check the Vaultwarden wiki for details on how to enable it"; ++ } + this.showToast(message); + break; + case "convertAccountToKeyConnector": +diff --git a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html +index 4690a4e63a..9d297671d2 100644 +--- a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html ++++ b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html +@@ -1,6 +1,6 @@ +

+
+- ++ +

+ +

+- ++ +

+ {{ "loginOrCreateNewAccount" | i18n }} +

+@@ -51,7 +51,7 @@ + +
+ +-
++
+

{{ "or" | i18n }}

+ + + +- +- +diff --git a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts +index 849e003440..de32156aad 100644 +--- a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts ++++ b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts +@@ -109,11 +109,11 @@ export class TwoFactorAuthenticatorComponent + new window.QRious({ + element: document.getElementById("qr"), + value: +- "otpauth://totp/Bitwarden:" + ++ "otpauth://totp/Vaultwarden:" + + Utils.encodeRFC3986URIComponent(email) + + "?secret=" + + encodeURIComponent(this.key) + +- "&issuer=Bitwarden", ++ "&issuer=Vaultwarden", + size: 160, + }); + }, 100); +diff --git a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts +index 78872aa6a9..eed953b91a 100644 +--- a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts ++++ b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts +@@ -44,7 +44,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy { + return; + } + this.loading = true; +- this.billing = await this.organizationApiService.getBilling(this.organizationId); ++ this.billing = null; + this.loading = false; + } + } +diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html +index a77d42a359..7de4e33fe2 100644 +--- a/apps/web/src/app/billing/organizations/organization-plans.component.html ++++ b/apps/web/src/app/billing/organizations/organization-plans.component.html +@@ -6,7 +6,7 @@ + >
+ {{ "loading" | i18n }} + +- ++ +

{{ "uploadLicenseFileOrg" | i18n }}

+
+
+@@ -28,7 +28,7 @@ + (ngSubmit)="submit()" + [appApiAction]="formPromise" + ngNativeValidate +- *ngIf="!loading && !selfHosted && this.passwordManagerPlans && this.secretsManagerPlans" ++ *ngIf="!loading" + class="tw-pt-6" + > + !!plan.PasswordManager); +@@ -186,6 +187,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + this.plan = providerDefaultPlan.type; + this.product = providerDefaultPlan.product; + } ++ end of asking /api/plans in Vaultwarden */ + + if (!this.createOrganization) { + this.upgradeFlowPrefillForm(); +@@ -257,6 +259,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get selectableProducts() { ++ return null; // there are no products to select in Vaultwarden + if (this.acceptingSponsorship) { + const familyPlan = this.passwordManagerPlans.find( + (plan) => plan.type === PlanType.FamiliesAnnually, +@@ -287,6 +290,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get selectablePlans() { ++ return null; // no plans to select in Vaultwarden + const selectedProductType = this.formGroup.controls.product.value; + const result = + this.passwordManagerPlans?.filter( +@@ -427,10 +431,12 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + get planOffersSecretsManager() { ++ return false; // no support for secrets manager in Vaultwarden + return this.selectedSecretsManagerPlan != null; + } + + changedProduct() { ++ return; // no choice of products in Vaultwarden + const selectedPlan = this.selectablePlans[0]; + + this.setPlanType(selectedPlan.type); +@@ -543,7 +549,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + const orgKeys = await this.cryptoService.makeKeyPair(orgKey[1]); + + if (this.selfHosted) { +- orgId = await this.createSelfHosted(key, collectionCt, orgKeys); ++ orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]); + } else { + orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]); + } +@@ -644,7 +650,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + request.billingEmail = this.formGroup.controls.billingEmail.value; + request.initiationPath = "New organization creation in-product"; + request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString); ++ request.planType = PlanType.Free; // always select the free plan in Vaultwarden + ++ /* there is no plan to select in Vaultwarden + if (this.selectedPlan.type === PlanType.Free) { + request.planType = PlanType.Free; + } else { +@@ -674,6 +682,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + + // Secrets Manager + this.buildSecretsManagerRequest(request); ++ end plan selection and no support for secret manager in Vaultwarden */ + + if (this.hasProvider) { + const providerRequest = new ProviderOrganizationCreateRequest( +@@ -755,6 +764,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { + } + + private upgradeFlowPrefillForm() { ++ return; // Vaultwarden only supports free plan + if (this.acceptingSponsorship) { + this.formGroup.controls.product.setValue(ProductType.Families); + this.changedProduct(); +diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts +index 2a47971147..b245534220 100644 +--- a/apps/web/src/app/core/init.service.ts ++++ b/apps/web/src/app/core/init.service.ts +@@ -7,10 +7,7 @@ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwar + import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; + import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service"; + import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; +-import { +- EnvironmentService as EnvironmentServiceAbstraction, +- Urls, +-} from "@bitwarden/common/platform/abstractions/environment.service"; ++import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/platform/abstractions/environment.service"; + import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; + import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; + import { ConfigService } from "@bitwarden/common/platform/services/config/config.service"; +@@ -36,11 +33,23 @@ export class InitService { + ) {} + + init() { ++ function getBaseUrl() { ++ // If the base URL is `https://vaultwarden.example.com/base/path/`, ++ // `window.location.href` should have one of the following forms: ++ // ++ // - `https://vaultwarden.example.com/base/path/` ++ // - `https://vaultwarden.example.com/base/path/#/some/route[?queryParam=...]` ++ // ++ // We want to get to just `https://vaultwarden.example.com/base/path`. ++ let baseUrl = window.location.href; ++ baseUrl = baseUrl.replace(/#.*/, ""); // Strip off `#` and everything after. ++ baseUrl = baseUrl.replace(/\/+$/, ""); // Trim any trailing `/` chars. ++ return baseUrl; ++ } + return async () => { + await this.stateService.init(); + +- const urls = process.env.URLS as Urls; +- urls.base ??= this.win.location.origin; ++ const urls = { base: getBaseUrl() }; + await this.environmentService.setUrls(urls); + // Workaround to ignore stateService.activeAccount until process.env.URLS are set + // TODO: Remove this when implementing ticket PM-2637 +diff --git a/apps/web/src/app/core/router.service.ts b/apps/web/src/app/core/router.service.ts +index 5a0d903ba7..d6fedadd38 100644 +--- a/apps/web/src/app/core/router.service.ts ++++ b/apps/web/src/app/core/router.service.ts +@@ -26,7 +26,7 @@ export class RouterService { + .subscribe((event: NavigationEnd) => { + this.currentUrl = event.url; + +- let title = i18nService.t("bitWebVault"); ++ let title = "Vaultwarden Web"; + + if (this.currentUrl.includes("/sm/")) { + title = i18nService.t("bitSecretsManager"); +diff --git a/apps/web/src/app/core/web-platform-utils.service.ts b/apps/web/src/app/core/web-platform-utils.service.ts +index 02c7c29e34..9fd100024a 100644 +--- a/apps/web/src/app/core/web-platform-utils.service.ts ++++ b/apps/web/src/app/core/web-platform-utils.service.ts +@@ -133,14 +133,17 @@ export class WebPlatformUtilsService implements PlatformUtilsService { + } + + isDev(): boolean { ++ return false; // treat Vaultwarden as production ready + return process.env.NODE_ENV === "development"; + } + + isSelfHost(): boolean { ++ return true; // treat Vaultwarden as self hosted + return WebPlatformUtilsService.isSelfHost(); + } + + static isSelfHost(): boolean { ++ return true; // treat Vaultwarden as self hosted + return process.env.ENV.toString() === "selfhosted"; + } + +diff --git a/apps/web/src/app/layouts/frontend-layout.component.html b/apps/web/src/app/layouts/frontend-layout.component.html +index 72f0f1f1da..cea0867131 100644 +--- a/apps/web/src/app/layouts/frontend-layout.component.html ++++ b/apps/web/src/app/layouts/frontend-layout.component.html +@@ -1,6 +1,11 @@ + +
+- +- © {{ year }} Bitwarden Inc.
++ Vaultwarden Web
+ {{ "versionNumber" | i18n: version }} ++

++
++ A modified version of the Bitwarden® Web Vault for Vaultwarden (an unofficial rewrite of the ++ Bitwarden® server).
++ Vaultwarden is not associated with the Bitwarden® project nor Bitwarden Inc. ++
+
+diff --git a/apps/web/src/app/layouts/header/web-header.component.html b/apps/web/src/app/layouts/header/web-header.component.html +index 514e5deebd..20165e5061 100644 +--- a/apps/web/src/app/layouts/header/web-header.component.html ++++ b/apps/web/src/app/layouts/header/web-header.component.html +@@ -76,7 +76,12 @@ + + {{ "accountSettings" | i18n }} +
+- ++ + + {{ "getHelp" | i18n }} + +diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html +index 9068f9c071..e051dccc85 100644 +--- a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html ++++ b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html +@@ -29,7 +29,7 @@ + + +
+ {{ "moreFromBitwarden" | i18n }} +diff --git a/apps/web/src/app/layouts/user-layout.component.html b/apps/web/src/app/layouts/user-layout.component.html +index 397e95d485..ac78bcb651 100644 +--- a/apps/web/src/app/layouts/user-layout.component.html ++++ b/apps/web/src/app/layouts/user-layout.component.html +@@ -33,8 +33,5 @@ + > + + +- + + +diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts +index e5c2f353c0..845d8b86ab 100644 +--- a/apps/web/src/app/oss-routing.module.ts ++++ b/apps/web/src/app/oss-routing.module.ts +@@ -222,13 +222,6 @@ const routes: Routes = [ + component: DomainRulesComponent, + data: { titleId: "domainRules" }, + }, +- { +- path: "subscription", +- loadChildren: () => +- import("./billing/individual/individual-billing.module").then( +- (m) => m.IndividualBillingModule, +- ), +- }, + { + path: "emergency-access", + children: [ +diff --git a/apps/web/src/app/settings/settings.component.ts b/apps/web/src/app/settings/settings.component.ts +index c2fd1c77fa..9e116d7f2c 100644 +--- a/apps/web/src/app/settings/settings.component.ts ++++ b/apps/web/src/app/settings/settings.component.ts +@@ -53,14 +53,7 @@ export class SettingsComponent implements OnInit, OnDestroy { + } + + async load() { +- this.premium = await this.stateService.getHasPremiumPersonally(); +- this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships(); +- const hasPremiumFromOrg = await this.stateService.getHasPremiumFromOrganization(); +- let billing = null; +- if (!this.selfHosted) { +- billing = await this.apiService.getUserBillingHistory(); +- } +- this.hideSubscription = +- !this.premium && hasPremiumFromOrg && (this.selfHosted || billing?.hasNoHistory); ++ this.hasFamilySponsorshipAvailable = false; // disable family Sponsorships in Vaultwarden ++ this.hideSubscription = true; // always hide subscriptions in Vaultwarden + } + } +diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts +index 586f207962..863efc8769 100644 +--- a/apps/web/src/app/shared/loose-components.module.ts ++++ b/apps/web/src/app/shared/loose-components.module.ts +@@ -58,7 +58,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 { PaymentMethodWarningsModule } from "../billing/shared"; + import { DynamicAvatarComponent } from "../components/dynamic-avatar.component"; + import { SelectableAvatarComponent } from "../components/selectable-avatar.component"; + import { FrontendLayoutComponent } from "../layouts/frontend-layout.component"; +@@ -111,7 +110,6 @@ import { SharedModule } from "./shared.module"; + HeaderModule, + OrganizationLayoutComponent, + UserLayoutComponent, +- PaymentMethodWarningsModule, + ], + declarations: [ + AcceptFamilySponsorshipComponent, +diff --git a/apps/web/src/app/tools/send/access.component.html b/apps/web/src/app/tools/send/access.component.html +index 6fef7d361d..1deb1164ff 100644 +--- a/apps/web/src/app/tools/send/access.component.html ++++ b/apps/web/src/app/tools/send/access.component.html +@@ -2,7 +2,7 @@ +
+- ++ +
+

View Send

+
+@@ -66,19 +66,6 @@ +
+

+ {{ "sendAccessTaglineProductDesc" | i18n }} +- {{ "sendAccessTaglineLearnMore" | i18n }} +- Bitwarden Send +- {{ "sendAccessTaglineOr" | i18n }} +- {{ +- "sendAccessTaglineSignUp" | i18n +- }} +- {{ "sendAccessTaglineTryToday" | i18n }} +

+
+
+diff --git a/apps/web/src/index.html b/apps/web/src/index.html +index c3a2c03ed9..1a326771a6 100644 +--- a/apps/web/src/index.html ++++ b/apps/web/src/index.html +@@ -5,7 +5,7 @@ + + + +- Bitwarden Web Vault ++ Vaultwarden Web + + + +@@ -17,7 +17,7 @@ + +
+
+- ++ +

+ form:nth-child(1) > div:nth-child(3) { ++ @extend %vw-hide; ++} ++ ++/* Hide the `This account is owned by a business` checkbox and label */ ++#ownedBusiness, ++label[for^="ownedBusiness"] { ++ @extend %vw-hide; ++} ++ ++/* Hide the radio button and label for the `Custom` org user type */ ++#userTypeCustom, ++label[for^="userTypeCustom"] { ++ @extend %vw-hide; ++} ++ ++/* Hide Business Name */ ++app-org-account form div bit-form-field.tw-block:nth-child(3) { ++ @extend %vw-hide; ++} ++ ++/* Hide organization plans */ ++app-organization-plans > form > h2.mt-5 { ++ @extend %vw-hide; ++} ++ ++/* Hide Device Verification form at the Two Step Login screen */ ++app-security > app-two-factor-setup > form { ++ @extend %vw-hide; ++} ++ ++/* Replace the Bitwarden Shield at the top left with a Vaultwarden icon */ ++.bwi-shield:before { ++ content: "" !important; ++ width: 32px !important; ++ height: 40px !important; ++ display: block !important; ++ background-image: url(../images/icon-white.png) !important; ++ background-repeat: no-repeat; ++ background-position-y: bottom; ++} ++/**** END Vaultwarden CHANGES ****/ +diff --git a/apps/web/src/scss/variables.scss b/apps/web/src/scss/variables.scss +index 9d3d8d6ad4..5bc773c0d8 100644 +--- a/apps/web/src/scss/variables.scss ++++ b/apps/web/src/scss/variables.scss +@@ -3,7 +3,7 @@ $dark-icon-themes: "theme_dark"; + $primary: #175ddc; + $primary-accent: #1252a3; + $secondary: #ced4da; +-$secondary-alt: #1a3b66; ++$secondary-alt: #212529; + $success: #017e45; + $info: #555555; + $warning: #8b6609; +diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js +index 6ac384cb82..0492e09476 100644 +--- a/apps/web/webpack.config.js ++++ b/apps/web/webpack.config.js +@@ -141,8 +141,6 @@ const plugins = [ + { from: "./src/favicon.ico" }, + { from: "./src/browserconfig.xml" }, + { from: "./src/app-id.json" }, +- { from: "./src/404.html" }, +- { from: "./src/404", to: "404" }, + { from: "./src/images", to: "images" }, + { from: "./src/locales", to: "locales" }, + { from: "../../node_modules/qrious/dist/qrious.min.js", to: "scripts" }, +diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts +index 3cffebe71b..c1229b5c2c 100644 +--- a/libs/angular/src/auth/components/register.component.ts ++++ b/libs/angular/src/auth/components/register.component.ts +@@ -106,6 +106,14 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn + } + + async submit(showToast = true) { ++ if (typeof crypto.subtle === "undefined") { ++ this.platformUtilsService.showToast( ++ "error", ++ "This browser requires HTTPS to use the web vault", ++ "Check the Vaultwarden wiki for details on how to enable it", ++ ); ++ return; ++ } + let email = this.formGroup.value.email; + email = email.trim().toLowerCase(); + let name = this.formGroup.value.name; +diff --git a/libs/angular/src/auth/components/two-factor-options.component.ts b/libs/angular/src/auth/components/two-factor-options.component.ts +index 4293eb9966..7a8e861e8d 100644 +--- a/libs/angular/src/auth/components/two-factor-options.component.ts ++++ b/libs/angular/src/auth/components/two-factor-options.component.ts +@@ -30,7 +30,9 @@ export class TwoFactorOptionsComponent implements OnInit { + } + + recover() { +- this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/recover-2fa"); ++ this.platformUtilsService.launchUri( ++ "https://bitwarden.com/help/two-step-recovery-code/#use-your-recovery-code", ++ ); + this.onRecoverSelected.emit(); + } + } +diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css +index 75a8fa6380..733dbe9413 100644 +--- a/libs/components/src/tw-theme.css ++++ b/libs/components/src/tw-theme.css +@@ -6,12 +6,12 @@ + --color-background: 255 255 255; + --color-background-alt: 251 251 251; + --color-background-alt2: 23 92 219; +- --color-background-alt3: 18 82 163; +- --color-background-alt4: 13 60 119; ++ --color-background-alt3: 33 37 41; /* bg of menu panel */ ++ --color-background-alt4: 16 18 21; /* bg of active menu item */ + +- --color-primary-300: 103 149 232; +- --color-primary-500: 23 93 220; +- --color-primary-700: 18 82 163; ++ --color-primary-300: 108 117 125; /* hover of menu items */ ++ --color-primary-500: 18 82 163; /* color of links and buttons */ ++ --color-primary-700: 13 60 119; /* hover of links and buttons */ + + --color-secondary-100: 240 240 240; + --color-secondary-300: 206 212 220;