+-
++
+
+
+
+-
++
+
+ {{ "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 88b695eb72..f9aafc450a 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
+@@ -112,11 +112,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 1bd6b99dd1..ed391eb94c 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 }}
+
+
+-
+-
++
+
+ {{ "getHelp" | i18n }}
+
+diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html
+index 17698367bf..e1ea9cbab4 100644
+--- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html
++++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html
+@@ -11,7 +11,7 @@
+
+
+ 0"
++ *ngIf="false"
+ class="tw-mt-2 tw-flex tw-w-full tw-flex-col tw-gap-2 tw-border-0 tw-border-t tw-border-solid tw-border-t-text-alt2"
+ >
+ {{ "moreFromBitwarden" | 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 62d8b6a075..ec8a14c115 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
+@@ -30,7 +30,7 @@
+
+
+ 0"
++ *ngIf="false"
+ class="tw-mt-4 tw-flex tw-w-full tw-flex-col tw-gap-2 tw-border-0 tw-border-t tw-border-solid tw-border-t-text-muted tw-p-2 tw-pb-0"
+ >
+ {{ "moreFromBitwarden" | i18n }}
+diff --git a/apps/web/src/app/layouts/user-layout.component.ts b/apps/web/src/app/layouts/user-layout.component.ts
+index 1ce8d4d227..ca8268adcc 100644
+--- a/apps/web/src/app/layouts/user-layout.component.ts
++++ b/apps/web/src/app/layouts/user-layout.component.ts
+@@ -1,7 +1,7 @@
+ import { CommonModule } from "@angular/common";
+ import { Component, OnInit } from "@angular/core";
+ import { RouterModule } from "@angular/router";
+-import { Observable, combineLatest, concatMap } from "rxjs";
++import { Observable, of } from "rxjs";
+
+ import { JslibModule } from "@bitwarden/angular/jslib.module";
+ import { ApiService } from "@bitwarden/common/abstractions/api.service";
+@@ -58,26 +58,7 @@ export class UserLayoutComponent implements OnInit {
+
+ await this.syncService.fullSync(false);
+
+- this.hasFamilySponsorshipAvailable$ = this.organizationService.canManageSponsorships$;
+-
+- // We want to hide the subscription menu for organizations that provide premium.
+- // Except if the user has premium personally or has a billing history.
+- this.showSubscription$ = combineLatest([
+- this.billingAccountProfileStateService.hasPremiumPersonally$,
+- this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$,
+- ]).pipe(
+- concatMap(async ([hasPremiumPersonally, hasPremiumFromOrg]) => {
+- const isCloud = !this.platformUtilsService.isSelfHost();
+-
+- let billing = null;
+- if (isCloud) {
+- // TODO: We should remove the need to call this!
+- billing = await this.apiService.getUserBillingHistory();
+- }
+-
+- const cloudAndBillingHistory = isCloud && !billing?.hasNoHistory;
+- return hasPremiumPersonally || !hasPremiumFromOrg || cloudAndBillingHistory;
+- }),
+- );
++ this.hasFamilySponsorshipAvailable$ = of(false); // disable family Sponsorships in Vaultwarden
++ this.showSubscription$ = of(false); // always hide subscriptions in Vaultwarden
+ }
+ }
+diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts
+index e543a6f083..343933b043 100644
+--- a/apps/web/src/app/oss-routing.module.ts
++++ b/apps/web/src/app/oss-routing.module.ts
+@@ -236,13 +236,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/platform/web-environment.service.ts b/apps/web/src/app/platform/web-environment.service.ts
+index c2eb37eea5..2b5ac93392 100644
+--- a/apps/web/src/app/platform/web-environment.service.ts
++++ b/apps/web/src/app/platform/web-environment.service.ts
+@@ -27,8 +27,17 @@ export class WebEnvironmentService extends DefaultEnvironmentService {
+ super(stateProvider, accountService);
+
+ // The web vault always uses the current location as the base url
+- const urls = process.env.URLS as Urls;
+- urls.base ??= this.win.location.origin;
++ // 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 = this.win.location.href;
++ baseUrl = baseUrl.replace(/#.*/, ""); // Strip off `#` and everything after.
++ baseUrl = baseUrl.replace(/\/+$/, ""); // Trim any trailing `/` chars.
++ const urls = { base: baseUrl };
+
+ // Find the region
+ const domain = Utils.getDomain(this.win.location.href);
+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/app/tools/send/add-edit.component.html b/apps/web/src/app/tools/send/add-edit.component.html
+index 3225b61350..2a192514bf 100644
+--- a/apps/web/src/app/tools/send/add-edit.component.html
++++ b/apps/web/src/app/tools/send/add-edit.component.html
+@@ -227,7 +227,12 @@
+ {{ "password" | i18n }}
+ {{ "newPassword" | i18n }}
+
+-
++
+
+ {{ "sendPasswordDesc" | i18n }}
+
+diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts
+index 8dd63e62dd..1a1e45cc35 100644
+--- a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts
++++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts
+@@ -10,6 +10,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
+ import { PolicyType } from "@bitwarden/common/admin-console/enums";
+ import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
+ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
++import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
+ 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";
+@@ -48,6 +49,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
+ private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
+ private dialogService: DialogService,
+ private resetPasswordService: OrganizationUserResetPasswordService,
++ private userVerificationService: UserVerificationService,
+ ) {}
+
+ async ngOnInit() {
+@@ -155,6 +157,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
+ this.i18nService,
+ this.syncService,
+ this.logService,
++ this.userVerificationService,
+ );
+ } else {
+ // Remove reset password
+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/tailwind.config.js b/apps/web/tailwind.config.js
+index 08673c3f9a..db1dd55694 100644
+--- a/apps/web/tailwind.config.js
++++ b/apps/web/tailwind.config.js
+@@ -6,7 +6,6 @@ config.content = [
+ "../../libs/components/src/**/*.{html,ts}",
+ "../../libs/auth/src/**/*.{html,ts}",
+ "../../libs/angular/src/**/*.{html,ts}",
+- "../../bitwarden_license/bit-web/src/**/*.{html,ts}",
+ ];
+
+ module.exports = config;
+diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js
+index f22d98f081..a9904a2ecf 100644
+--- a/apps/web/webpack.config.js
++++ b/apps/web/webpack.config.js
+@@ -138,8 +138,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/clients.code-workspace b/clients.code-workspace
+index a424f91eeb..72f7c59185 100644
+--- a/clients.code-workspace
++++ b/clients.code-workspace
+@@ -8,18 +8,10 @@
+ "name": "web vault",
+ "path": "apps/web",
+ },
+- {
+- "name": "web vault (bit)",
+- "path": "bitwarden_license/bit-web",
+- },
+ {
+ "name": "cli",
+ "path": "apps/cli",
+ },
+- {
+- "name": "cli (bit)",
+- "path": "bitwarden_license/bit-cli",
+- },
+ {
+ "name": "desktop",
+ "path": "apps/desktop",
+@@ -32,10 +24,6 @@
+ "name": "libs",
+ "path": "libs",
+ },
+- {
+- "name": "common (bit)",
+- "path": "bitwarden_license/bit-common",
+- },
+ ],
+ "settings": {
+ "eslint.options": {
+diff --git a/jest.config.js b/jest.config.js
+index f4e97262a3..12e11b35a3 100644
+--- a/jest.config.js
++++ b/jest.config.js
+@@ -20,9 +20,6 @@ module.exports = {
+ "/apps/cli/jest.config.js",
+ "/apps/desktop/jest.config.js",
+ "/apps/web/jest.config.js",
+- "/bitwarden_license/bit-web/jest.config.js",
+- "/bitwarden_license/bit-cli/jest.config.js",
+- "/bitwarden_license/bit-common/jest.config.js",
+
+ "/libs/admin-console/jest.config.js",
+ "/libs/angular/jest.config.js",
+diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts
+index e3197355dc..e3004ebdf7 100644
+--- a/libs/angular/src/auth/components/register.component.ts
++++ b/libs/angular/src/auth/components/register.component.ts
+@@ -110,6 +110,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/auth/src/angular/user-verification/user-verification-dialog.component.html b/libs/auth/src/angular/user-verification/user-verification-dialog.component.html
+index aa4d26ae61..fb3b7cf4cb 100644
+--- a/libs/auth/src/angular/user-verification/user-verification-dialog.component.html
++++ b/libs/auth/src/angular/user-verification/user-verification-dialog.component.html
+@@ -9,8 +9,8 @@
+
+
+@@ -29,7 +29,7 @@
+
+
+@@ -41,7 +41,7 @@
+
+@@ -50,8 +50,8 @@
+
+
+@@ -85,10 +85,12 @@
+
+-
++
+
+diff --git a/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts b/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts
+index 7b2c869e3a..f8746b5b24 100644
+--- a/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts
++++ b/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts
+@@ -142,6 +142,31 @@ export class UserVerificationDialogComponent {
+ * return;
+ * }
+ *
++ * ----------------------------------------------------------
++ *
++ * @example
++ * // Example 4: Custom user verification validation
++ *
++ * const result = await UserVerificationDialogComponent.open(dialogService, {
++ * verificationType: {
++ * type: "custom",
++ * // Pass in a function that will be used to validate the input of the
++ * // verification dialog, returning true when finished.
++ * verificationFn: async (secret: VerificationWithSecret) => {
++ * const request = await userVerificationService.buildRequest(secret);
++ *
++ * // ... Do something with the custom request type
++ *
++ * await someServicer.sendMyRequestThatVerfiesUserIdentity(
++ * // ... Some other data
++ * request,
++ * );
++ * return true;
++ * },
++ * },
++ * });
++ *
++ * // ... Evaluate the result as usual
+ */
+ static async open(
+ dialogService: DialogService,
+@@ -202,6 +227,18 @@ export class UserVerificationDialogComponent {
+ }
+
+ try {
++ if (
++ typeof this.dialogOptions.verificationType === "object" &&
++ this.dialogOptions.verificationType.type === "custom"
++ ) {
++ const success = await this.dialogOptions.verificationType.verificationFn(this.secret.value);
++ this.close({
++ userAction: "confirm",
++ verificationSuccess: success,
++ });
++ return;
++ }
++
+ // TODO: once we migrate all user verification scenarios to use this new implementation,
+ // we should consider refactoring the user verification service handling of the
+ // OTP and MP flows to not throw errors on verification failure.
+diff --git a/libs/auth/src/angular/user-verification/user-verification-dialog.types.ts b/libs/auth/src/angular/user-verification/user-verification-dialog.types.ts
+index f4637c770a..cb03f4e18f 100644
+--- a/libs/auth/src/angular/user-verification/user-verification-dialog.types.ts
++++ b/libs/auth/src/angular/user-verification/user-verification-dialog.types.ts
+@@ -1,3 +1,4 @@
++import { VerificationWithSecret } from "@bitwarden/common/auth/types/verification";
+ import { ButtonType } from "@bitwarden/components";
+
+ /**
+@@ -60,12 +61,27 @@ export type UserVerificationDialogOptions = {
+ */
+ confirmButtonOptions?: UserVerificationConfirmButtonOptions;
+
+- /**
+- * Indicates whether the verification is only performed client-side. Includes local MP verification, PIN, and Biometrics.
+- * Optional.
+- * **Important:** Only for use on desktop and browser platforms as when there are no client verification methods, the user is instructed to set a pin (which is not supported on web)
++ /** The validation method used to verify the secret.
++ *
++ * Possible values:
++ *
++ * - "default": Perform the default validation operation for the determined
++ * secret type. This would, for example, validate master passwords
++ * locally but OTPs on the server.
++ * - "client": Only do a client-side verification with no possible server
++ * request. Includes local MP verification, PIN, and Biometrics.
++ * **Important:** This option is only for use on desktop and browser
++ * platforms. When there are no client verification methods the user is
++ * instructed to set a pin, and this is not supported on web.
++ * - "custom": Custom validation is done to verify the secret. This is
++ * passed in from callers when opening the dialog. The custom type is
++ * meant to provide a mechanism where users can call a secured endpoint
++ * that performs user verification server side.
+ */
+- clientSideOnlyVerification?: boolean;
++ verificationType?:
++ | "default"
++ | "client"
++ | { type: "custom"; verificationFn: (secret: VerificationWithSecret) => Promise };
+ };
+
+ /**
+diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css
+index 00ab2ff717..0950b9d787 100644
+--- a/libs/components/src/tw-theme.css
++++ b/libs/components/src/tw-theme.css
+@@ -14,16 +14,16 @@
+ --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 */
+
+ /* Can only be used behind the extension refresh flag */
+ --color-primary-100: 200 217 249;
+- --color-primary-300: 103 149 232;
++ --color-primary-300: 108 117 125; /* hover of menu items */
+ /* Can only be used behind the extension refresh flag */
+ --color-primary-500: 23 93 220;
+- --color-primary-600: 23 93 220;
+- --color-primary-700: 18 82 163;
++ --color-primary-600: 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;
+diff --git a/libs/components/tailwind.config.js b/libs/components/tailwind.config.js
+index 7a53c82ec5..9d0a337bd2 100644
+--- a/libs/components/tailwind.config.js
++++ b/libs/components/tailwind.config.js
+@@ -6,7 +6,6 @@ config.content = [
+ "libs/auth/src/**/*.{html,ts,mdx}",
+ "apps/web/src/**/*.{html,ts,mdx}",
+ "apps/browser/src/**/*.{html,ts,mdx}",
+- "bitwarden_license/bit-web/src/**/*.{html,ts,mdx}",
+ ".storybook/preview.tsx",
+ ];
+ config.safelist = [
+diff --git a/tailwind.config.js b/tailwind.config.js
+index 50d82bf7d8..9b543ed950 100644
+--- a/tailwind.config.js
++++ b/tailwind.config.js
+@@ -9,7 +9,6 @@ config.content = [
+ "./libs/platform/src/**/*.{html,ts,mdx}",
+ "./libs/vault/src/**/*.{html,ts,mdx}",
+ "./apps/web/src/**/*.{html,ts,mdx}",
+- "./bitwarden_license/bit-web/src/**/*.{html,ts,mdx}",
+ "./.storybook/preview.js",
+ ];
+ config.safelist = [
+diff --git a/tsconfig.json b/tsconfig.json
+index 8085b9f832..81a954ec84 100644
+--- a/tsconfig.json
++++ b/tsconfig.json
+@@ -33,8 +33,7 @@
+ "@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"],
+ "@bitwarden/node/*": ["./libs/node/src/*"],
+ "@bitwarden/web-vault/*": ["./apps/web/src/*"],
+- "@bitwarden/vault": ["./libs/vault/src"],
+- "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"]
++ "@bitwarden/vault": ["./libs/vault/src"]
+ },
+ "plugins": [
+ {
+@@ -43,13 +42,7 @@
+ ],
+ "useDefineForClassFields": false
+ },
+- "include": [
+- "apps/web/src/**/*",
+- "apps/browser/src/**/*",
+- "libs/*/src/**/*",
+- "bitwarden_license/bit-web/src/**/*",
+- "bitwarden_license/bit-common/src/**/*"
+- ],
++ "include": ["apps/web/src/**/*", "apps/browser/src/**/*", "libs/*/src/**/*"],
+ "exclude": [
+ "apps/web/src/**/*.spec.ts",
+ "apps/browser/src/**/*.spec.ts",