diff --git a/.dockerignore b/.dockerignore
index 1f89afb..6ebf81e 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -8,11 +8,18 @@ web-vault
*.md
*.txt
-# Other
+# IDE files
+.vscode
+.idea
+*.iml
+
+# Environment files
.env
+.build_env
+
+# Other
.github
Makefile
-.vscode
# Release files
*.tar.gz
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..3d036b8
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,3 @@
+/.github @dani-garcia @BlackDex
+/.github/CODEOWNERS @dani-garcia @BlackDex
+/.github/workflows/** @dani-garcia @BlackDex
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..6e92bbd
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+name: CI
+
+on:
+ pull_request:
+ paths:
+ - ".github/workflows/ci.yml"
+ - "patches/v20*.patch"
+ - "resources/**"
+ - "scripts/**"
+ - "Dockerfile"
+
+jobs:
+ docker-build:
+ runs-on: ubuntu-latest
+ env:
+ # Force docker to output the progress in plain
+ BUILDKIT_PROGRESS: plain
+ steps:
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Build and Extract
+ shell: bash
+ run: |
+ make docker-extract
+
+ - name: Generate checksum
+ shell: bash
+ run: |
+ echo "sha256sum: $(sha256sum container_builds/bw_web_vault.tar.gz)"
+
+ - name: "Upload web-vault artifact"
+ uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
+ with:
+ name: web-vault
+ compression-level: 0
+ path: container_builds/bw_web_vault.tar.gz
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index dffd084..667fc1c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -19,7 +19,7 @@ jobs:
HAVE_GHCR_LOGIN: ${{ vars.GHCR_REPO != '' && github.repository_owner != '' && secrets.GITHUB_TOKEN != '' }}
steps:
- name: Checkout
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Determine Docker Tag
- name: Init Variables
@@ -64,7 +64,7 @@ jobs:
| tee -a "${GITHUB_ENV}"
- name: Build and push
- uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 # v6.5.0
+ uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
with:
context: .
push: true
diff --git a/.gitignore b/.gitignore
index c015c05..5137943 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,17 @@
# Local build artifacts
-builds/
-docker_builds/
-container_builds/
-web-vault/
+builds
+docker_builds
+container_builds
+web-vault
-# Other
+# IDE files
+.vscode
+.idea
+*.iml
+
+# Environment files
.env
.build_env
-.vscode
# Release files
*.tar.gz
diff --git a/Dockerfile b/Dockerfile
index 4427ed9..a19fa9d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,8 +23,8 @@ RUN node --version && npm --version
# 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.6.2
-ARG VAULT_VERSION=e2354e8694ab5e532d04f275e4bd6bf560c7509b
+# Using https://github.com/bitwarden/clients/releases/tag/web-v2024.12.0
+ARG VAULT_VERSION=e0c8f2ced997fc279c8ded903471ca3fa0fe5e94
ENV VAULT_VERSION=$VAULT_VERSION
ENV VAULT_FOLDER=bw_clients
ENV CHECKOUT_TAGS=false
@@ -45,7 +45,7 @@ RUN mv "${VAULT_FOLDER}/apps/web/build" ./web-vault
RUN tar -czvf "bw_web_vault.tar.gz" web-vault --owner=0 --group=0
# Output the sha256sum here so people are able to match the sha256sum from the CI with the assets and the downloaded version if needed
-RUN echo "sha256sum: $(sha256sum "bw_web_vault.tar.gz")"
+RUN echo "sha256sum: $(sha256sum bw_web_vault.tar.gz)"
# We copy the final result as a separate empty image so there's no need to download all the intermediate steps
# The result is included both uncompressed and as a tar.gz, to be able to use it in the docker images and the github releases directly
diff --git a/patches/v2023.1.0.patch b/patches/legacy/v2023.1.0.patch
similarity index 100%
rename from patches/v2023.1.0.patch
rename to patches/legacy/v2023.1.0.patch
diff --git a/patches/v2023.1.1.patch b/patches/legacy/v2023.1.1.patch
similarity index 100%
rename from patches/v2023.1.1.patch
rename to patches/legacy/v2023.1.1.patch
diff --git a/patches/v2023.10.0.patch b/patches/legacy/v2023.10.0.patch
similarity index 100%
rename from patches/v2023.10.0.patch
rename to patches/legacy/v2023.10.0.patch
diff --git a/patches/v2023.12.0.patch b/patches/legacy/v2023.12.0.patch
similarity index 100%
rename from patches/v2023.12.0.patch
rename to patches/legacy/v2023.12.0.patch
diff --git a/patches/v2023.2.0.patch b/patches/legacy/v2023.2.0.patch
similarity index 100%
rename from patches/v2023.2.0.patch
rename to patches/legacy/v2023.2.0.patch
diff --git a/patches/v2023.3.0.patch b/patches/legacy/v2023.3.0.patch
similarity index 100%
rename from patches/v2023.3.0.patch
rename to patches/legacy/v2023.3.0.patch
diff --git a/patches/v2023.4.0.patch b/patches/legacy/v2023.4.0.patch
similarity index 100%
rename from patches/v2023.4.0.patch
rename to patches/legacy/v2023.4.0.patch
diff --git a/patches/v2023.5.0.patch b/patches/legacy/v2023.5.0.patch
similarity index 100%
rename from patches/v2023.5.0.patch
rename to patches/legacy/v2023.5.0.patch
diff --git a/patches/v2023.5.1.patch b/patches/legacy/v2023.5.1.patch
similarity index 100%
rename from patches/v2023.5.1.patch
rename to patches/legacy/v2023.5.1.patch
diff --git a/patches/v2023.7.1.patch b/patches/legacy/v2023.7.1.patch
similarity index 100%
rename from patches/v2023.7.1.patch
rename to patches/legacy/v2023.7.1.patch
diff --git a/patches/v2023.8.2.patch b/patches/legacy/v2023.8.2.patch
similarity index 100%
rename from patches/v2023.8.2.patch
rename to patches/legacy/v2023.8.2.patch
diff --git a/patches/v2023.9.1.patch b/patches/legacy/v2023.9.1.patch
similarity index 100%
rename from patches/v2023.9.1.patch
rename to patches/legacy/v2023.9.1.patch
diff --git a/patches/v2024.10.5.patch b/patches/v2024.10.5.patch
new file mode 100644
index 0000000..fc4bf44
--- /dev/null
+++ b/patches/v2024.10.5.patch
@@ -0,0 +1,848 @@
+diff --git a/apps/web/package.json b/apps/web/package.json
+index 21274fbd80..3cfbc278a6 100644
+--- a/apps/web/package.json
++++ b/apps/web/package.json
+@@ -3,11 +3,8 @@
+ "version": "2024.10.5",
+ "scripts": {
+ "build:oss": "webpack",
+- "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",
+ "build:oss:watch": "webpack serve",
+- "build:bit:watch": "webpack serve -c ../../bitwarden_license/bit-web/webpack.config.js",
+ "build:bit:dev": "cross-env ENV=development npm run build:bit",
+- "build:bit:dev:analyze": "cross-env LOGGING=false webpack -c ../../bitwarden_license/bit-web/webpack.config.js --profile --json > stats.json && npx webpack-bundle-analyzer stats.json build/",
+ "build:bit:dev:watch": "cross-env ENV=development NODE_OPTIONS=\"--max-old-space-size=8192\" npm run build:bit:watch",
+ "build:bit:qa": "cross-env NODE_ENV=production ENV=qa npm run build:bit",
+ "build:bit:euprd": "cross-env NODE_ENV=production ENV=euprd npm run build:bit",
+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 e0a8006081..789efd9264 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 0beb87c81c..d1e5961c2b 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
+@@ -142,6 +142,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/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts
+index 3cc73c84a9..4f8f756298 100644
+--- a/apps/web/src/app/admin-console/organizations/members/members.component.ts
++++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts
+@@ -193,11 +193,7 @@ export class MembersComponent extends BaseMembersComponent
+ .find((p) => p.organizationId === this.organization.id);
+ this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
+
+- const billingMetadata = await this.billingApiService.getOrganizationBillingMetadata(
+- this.organization.id,
+- );
+-
+- this.orgIsOnSecretsManagerStandalone = billingMetadata.isOnSecretsManagerStandalone;
++ this.orgIsOnSecretsManagerStandalone = false; // don't get billing metadata
+
+ await this.load();
+
+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 d1a1a09192..0df5c1533d 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
+@@ -16,7 +16,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 67e94fad37..b27d532d98 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
+@@ -96,7 +96,7 @@ export class AccountComponent implements OnInit, OnDestroy {
+ ) {}
+
+ async ngOnInit() {
+- this.selfHosted = this.platformUtilsService.isSelfHost();
++ this.selfHosted = false; // set to false so we can rename organizations
+
+ this.configService
+ .getFeatureFlag$(FeatureFlag.LimitCollectionCreationDeletionSplit)
+@@ -209,6 +209,7 @@ export class AccountComponent implements OnInit, OnDestroy {
+ };
+
+ submitCollectionManagement = async () => {
++ return; // flexible collections are not supported by Vaultwarden
+ // Early exit if self-hosted
+ if (this.selfHosted && !this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
+ return;
+diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
+index 7cefdd2165..1573c0ce5f 100644
+--- a/apps/web/src/app/app.component.ts
++++ b/apps/web/src/app/app.component.ts
+@@ -232,6 +232,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.toastService._showToast(message);
+ break;
+ case "convertAccountToKeyConnector":
+diff --git a/apps/web/src/app/auth/login/login.component.html b/apps/web/src/app/auth/login/login.component.html
+index d26e81b35b..3897dc6abc 100644
+--- a/apps/web/src/app/auth/login/login.component.html
++++ b/apps/web/src/app/auth/login/login.component.html
+@@ -30,7 +30,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 da5378f479..6d80d96ff5 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
+@@ -187,11 +187,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,
+ });
+ }
+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 30ae39d481..37e2db43d2 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
+@@ -52,6 +52,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
+
+ this.loading = true;
+
++ /* disable billing history
+ const openInvoicesPromise = this.organizationBillingApiService.getBillingInvoices(
+ this.organizationId,
+ "open",
+@@ -85,6 +86,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
+ openInvoices.length <= pageSize ||
+ paidInvoices.length <= pageSize ||
+ transactions.length <= pageSize;
++ */
+
+ 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 16c5259e8a..3f758ff68d 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 08195d95bf..f51a216a14 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
+@@ -10,10 +10,7 @@
+ >
+
+
+- 0"
+- class="tw-mt-2 tw-flex tw-w-full tw-flex-col tw-gap-2 tw-border-0"
+- >
++
+ {{ "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 41346675bb..d366fdf7d7 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 bd02533233..072465f7af 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";
+@@ -38,26 +38,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/platform/web-environment.service.ts b/apps/web/src/app/platform/web-environment.service.ts
+index ebddc7491b..7e12389a4a 100644
+--- a/apps/web/src/app/platform/web-environment.service.ts
++++ b/apps/web/src/app/platform/web-environment.service.ts
+@@ -36,7 +36,17 @@ export class WebEnvironmentService extends DefaultEnvironmentService {
+ super(stateProvider, accountService, additionalRegionConfigs);
+
+ // The web vault always uses the current location as the base url
+- envUrls.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=...]`
++ // - `https://vaultwarden.example.com/base/path/?queryParam=...`
++ //
++ // We want to get to just `https://vaultwarden.example.com/base/path`.
++ let baseUrl = this.win.location.href;
++ baseUrl = baseUrl.replace(/(\/+|\/*#.*|\/*\?.*)$/, ""); // Strip off trailing `/`, `#`, `?` and everything after.
++ envUrls.base ??= baseUrl;
+
+ // Find the region
+ const currentHostname = new URL(this.win.location.href).hostname;
+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 7eade18a7c..b8f865faa7 100644
+--- a/apps/web/src/app/tools/send/add-edit.component.html
++++ b/apps/web/src/app/tools/send/add-edit.component.html
+@@ -230,7 +230,12 @@
+ {{ "password" | i18n }}
+ {{ "newPassword" | i18n }}
+
+-
++
+
+ {{ "sendPasswordDesc" | i18n }}
+
+diff --git a/apps/web/src/app/tools/send/send-access-explainer.component.html b/apps/web/src/app/tools/send/send-access-explainer.component.html
+index e8090cb850..284b916514 100644
+--- a/apps/web/src/app/tools/send/send-access-explainer.component.html
++++ b/apps/web/src/app/tools/send/send-access-explainer.component.html
+@@ -1,18 +1,5 @@
+
+
+ {{ "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 ce1a955b88..ec0f30b18c 100644
+--- a/apps/web/src/index.html
++++ b/apps/web/src/index.html
+@@ -1,11 +1,11 @@
+-
++
+
+
+
+
+
+
+- Bitwarden Web vault
++ Vaultwarden Web
+
+
+
+@@ -16,7 +16,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 > bit-section:nth-child(2) {
++ @extend %vw-hide;
++}
++
++/* Hide Device Verification form at the Two Step Login screen */
++app-security > app-two-factor-setup > form {
++ @extend %vw-hide;
++}
++/**** END Vaultwarden CHANGES ****/
+diff --git a/apps/web/src/scss/tailwind.css b/apps/web/src/scss/tailwind.css
+index 1ac7b15401..0c388f6787 100644
+--- a/apps/web/src/scss/tailwind.css
++++ b/apps/web/src/scss/tailwind.css
+@@ -52,7 +52,7 @@
+ img.new-logo-themed {
+ @apply tw-block;
+
+- width: 128px;
++ width: 175px;
+ }
+ .theme_light img.new-logo-themed {
+ content: url("../images/logo.svg");
+diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js
+index 3ae0778250..868ee00eb0 100644
+--- a/apps/web/tailwind.config.js
++++ b/apps/web/tailwind.config.js
+@@ -7,7 +7,6 @@ config.content = [
+ "../../libs/auth/src/**/*.{html,ts}",
+ "../../libs/vault/src/**/*.{html,ts}",
+ "../../libs/angular/src/**/*.{html,ts}",
+- "../../bitwarden_license/bit-web/src/**/*.{html,ts}",
+ ];
+
+ module.exports = config;
+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 829adf1bf7..8f4bd4b5db 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 60adcba4d9..1406493881 100644
+--- a/libs/angular/src/auth/components/register.component.ts
++++ b/libs/angular/src/auth/components/register.component.ts
+@@ -111,6 +111,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/anon-layout/anon-layout-wrapper.component.ts b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts
+index 2744633574..35918bf6f7 100644
+--- a/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts
++++ b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts
+@@ -6,6 +6,8 @@ import { AnonLayoutComponent } from "@bitwarden/auth/angular";
+ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
+ import { Icon, Translation } from "@bitwarden/components";
+
++import { BitwardenShield } from "../icons";
++
+ import { AnonLayoutWrapperDataService } from "./anon-layout-wrapper-data.service";
+
+ export interface AnonLayoutWrapperData {
+@@ -148,7 +150,7 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
+ private resetPageData() {
+ this.pageTitle = null;
+ this.pageSubtitle = null;
+- this.pageIcon = null;
++ this.pageIcon = BitwardenShield;
+ this.showReadonlyHostname = null;
+ this.maxWidth = null;
+ }
+diff --git a/libs/auth/src/angular/anon-layout/anon-layout.component.html b/libs/auth/src/angular/anon-layout/anon-layout.component.html
+index 8a0ac4b718..85d957a28d 100644
+--- a/libs/auth/src/angular/anon-layout/anon-layout.component.html
++++ b/libs/auth/src/angular/anon-layout/anon-layout.component.html
+@@ -8,7 +8,7 @@
+ 'tw-min-h-full': clientType === 'browser' || clientType === 'desktop',
+ }"
+ >
+-
++
+
+
+
+@@ -51,8 +51,14 @@
+
+
+
+- © {{ year }} Bitwarden Inc.
+- {{ version }}
++ Vaultwarden Web
++ Version {{ 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/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css
+index 7214ae73ef..83cbf9d162 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;
+@@ -52,7 +52,7 @@
+ --color-text-code: 192 17 118;
+ --color-text-headers: 2 15 102;
+
+- --color-marketing-logo: 23 93 220;
++ --color-marketing-logo: 15 15 15;
+
+ --tw-ring-offset-color: #ffffff;
+ }
+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 637c28a54e..7afcea4e65 100644
+--- a/tailwind.config.js
++++ b/tailwind.config.js
+@@ -10,7 +10,6 @@ config.content = [
+ "./libs/tools/send/send-ui/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 225321663c..7a7dde454f 100644
+--- a/tsconfig.json
++++ b/tsconfig.json
+@@ -37,8 +37,7 @@
+ "@bitwarden/tools-card": ["./libs/tools/card/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": [
+ {
+@@ -52,9 +51,7 @@
+ "apps/browser/src/**/*",
+ "libs/*/src/**/*",
+ "libs/tools/send/**/src/**/*",
+- "libs/tools/card/src/**/*",
+- "bitwarden_license/bit-web/src/**/*",
+- "bitwarden_license/bit-common/src/**/*"
++ "libs/tools/card/src/**/*"
+ ],
+ "exclude": [
+ "apps/web/src/**/*.spec.ts",
diff --git a/patches/v2024.11.2.patch b/patches/v2024.11.2.patch
new file mode 100644
index 0000000..9f764be
--- /dev/null
+++ b/patches/v2024.11.2.patch
@@ -0,0 +1,796 @@
+diff --git a/apps/web/config/base.json b/apps/web/config/base.json
+index cfaf604fb0..804252469a 100644
+--- a/apps/web/config/base.json
++++ b/apps/web/config/base.json
+@@ -1,11 +1,5 @@
+ {
+ "urls": {},
+- "stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD",
+- "braintreeKey": "sandbox_r72q8jq6_9pnxkwm75f87sdc2",
+- "paypal": {
+- "businessId": "AD3LAUZSNVPJY",
+- "buttonAction": "https://www.sandbox.paypal.com/cgi-bin/webscr"
+- },
+ "dev": {
+ "port": 8080,
+ "allowedHosts": "auto"
+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 e0a8006081..789efd9264 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 0beb87c81c..d1e5961c2b 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
+@@ -142,6 +142,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/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts
+index 394c900f8d..7ef8fb741f 100644
+--- a/apps/web/src/app/admin-console/organizations/members/members.component.ts
++++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts
+@@ -193,11 +193,7 @@ export class MembersComponent extends BaseMembersComponent
+ .find((p) => p.organizationId === this.organization.id);
+ this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
+
+- const billingMetadata = await this.billingApiService.getOrganizationBillingMetadata(
+- this.organization.id,
+- );
+-
+- this.orgIsOnSecretsManagerStandalone = billingMetadata.isOnSecretsManagerStandalone;
++ this.orgIsOnSecretsManagerStandalone = false; // don't get billing metadata
+
+ await this.load();
+
+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 a36b267e2f..538cc45ac6 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
+@@ -62,13 +62,6 @@ const routes: Routes = [
+ (m) => m.OrganizationReportingModule,
+ ),
+ },
+- {
+- path: "access-intelligence",
+- loadChildren: () =>
+- import("../../tools/access-intelligence/access-intelligence.module").then(
+- (m) => m.AccessIntelligenceModule,
+- ),
+- },
+ {
+ path: "billing",
+ loadChildren: () =>
+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 d1a1a09192..0df5c1533d 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
+@@ -16,7 +16,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 2d97f95e51..820a01da50 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
+@@ -96,7 +96,7 @@ export class AccountComponent implements OnInit, OnDestroy {
+ ) {}
+
+ async ngOnInit() {
+- this.selfHosted = this.platformUtilsService.isSelfHost();
++ this.selfHosted = false; // set to false so we can rename organizations
+
+ this.configService
+ .getFeatureFlag$(FeatureFlag.LimitCollectionCreationDeletionSplit)
+@@ -211,6 +211,7 @@ export class AccountComponent implements OnInit, OnDestroy {
+ };
+
+ submitCollectionManagement = async () => {
++ return; // flexible collections are not supported by Vaultwarden
+ // Early exit if self-hosted
+ if (this.selfHosted && !this.limitCollectionCreationDeletionSplitFeatureFlagIsEnabled) {
+ return;
+diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
+index 704960c14c..0cc7bbf9c1 100644
+--- a/apps/web/src/app/app.component.ts
++++ b/apps/web/src/app/app.component.ts
+@@ -231,6 +231,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.toastService._showToast(message);
+ break;
+ case "convertAccountToKeyConnector":
+diff --git a/apps/web/src/app/auth/settings/change-password.component.html b/apps/web/src/app/auth/settings/change-password.component.html
+index 91144fdfc1..d3dc4410c9 100644
+--- a/apps/web/src/app/auth/settings/change-password.component.html
++++ b/apps/web/src/app/auth/settings/change-password.component.html
+@@ -125,5 +125,3 @@
+ {{ "changeMasterPassword" | 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 da5378f479..6d80d96ff5 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
+@@ -187,11 +187,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,
+ });
+ }
+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 30ae39d481..37e2db43d2 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
+@@ -52,6 +52,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
+
+ this.loading = true;
+
++ /* disable billing history
+ const openInvoicesPromise = this.organizationBillingApiService.getBillingInvoices(
+ this.organizationId,
+ "open",
+@@ -85,6 +86,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
+ openInvoices.length <= pageSize ||
+ paidInvoices.length <= pageSize ||
+ transactions.length <= pageSize;
++ */
+
+ 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 e1b74abea7..aff83361b6 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 }}
+
+-