mirror of
https://github.com/bitwarden/server.git
synced 2025-06-24 12:48:48 -05:00
Merge branch 'main' into dirt/pm-20574/database_tables_and_scripts_riskinsights
This commit is contained in:
commit
4b952b1109
@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"swashbuckle.aspnetcore.cli": {
|
||||
"version": "7.2.0",
|
||||
"version": "7.3.2",
|
||||
"commands": ["swagger"]
|
||||
},
|
||||
"dotnet-ef": {
|
||||
|
7
.github/renovate.json5
vendored
7
.github/renovate.json5
vendored
@ -15,8 +15,7 @@
|
||||
matchManagers: ["github-actions"],
|
||||
matchFileNames: [
|
||||
".github/workflows/publish.yml",
|
||||
".github/workflows/release.yml",
|
||||
".github/workflows/repository-management.yml"
|
||||
".github/workflows/release.yml"
|
||||
],
|
||||
commitMessagePrefix: "[deps] BRE:",
|
||||
reviewers: ["team:dept-bre"],
|
||||
@ -134,8 +133,8 @@
|
||||
reviewers: ["team:dept-dbops"],
|
||||
},
|
||||
{
|
||||
matchPackageNames: ["CommandDotNet", "YamlDotNet"],
|
||||
description: "DevOps owned dependencies",
|
||||
matchPackageNames: ["YamlDotNet"],
|
||||
description: "BRE owned dependencies",
|
||||
commitMessagePrefix: "[deps] BRE:",
|
||||
reviewers: ["team:dept-bre"],
|
||||
},
|
||||
|
224
.github/workflows/build.yml
vendored
224
.github/workflows/build.yml
vendored
@ -11,6 +11,9 @@ on:
|
||||
types: [opened, synchronize]
|
||||
workflow_call:
|
||||
inputs: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
_AZ_REGISTRY: "bitwardenprod.azurecr.io"
|
||||
@ -19,7 +22,7 @@ env:
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
@ -33,115 +36,15 @@ jobs:
|
||||
run: dotnet format --verify-no-changes
|
||||
|
||||
build-artifacts:
|
||||
name: Build artifacts
|
||||
runs-on: ubuntu-22.04
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- lint
|
||||
outputs:
|
||||
has_secrets: ${{ steps.check-secrets.outputs.has_secrets }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- project_name: Admin
|
||||
base_path: ./src
|
||||
node: true
|
||||
- project_name: Api
|
||||
base_path: ./src
|
||||
- project_name: Billing
|
||||
base_path: ./src
|
||||
- project_name: Events
|
||||
base_path: ./src
|
||||
- project_name: EventsProcessor
|
||||
base_path: ./src
|
||||
- project_name: Icons
|
||||
base_path: ./src
|
||||
- project_name: Identity
|
||||
base_path: ./src
|
||||
- project_name: MsSqlMigratorUtility
|
||||
base_path: ./util
|
||||
dotnet: true
|
||||
- project_name: Notifications
|
||||
base_path: ./src
|
||||
- project_name: Scim
|
||||
base_path: ./bitwarden_license/src
|
||||
dotnet: true
|
||||
- project_name: Server
|
||||
base_path: ./util
|
||||
- project_name: Setup
|
||||
base_path: ./util
|
||||
- project_name: Sso
|
||||
base_path: ./bitwarden_license/src
|
||||
node: true
|
||||
steps:
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
env:
|
||||
AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
node-version: "16"
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
whoami
|
||||
dotnet --info
|
||||
node --version
|
||||
npm --version
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Build node
|
||||
if: ${{ matrix.node }}
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Publish project
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
echo "Publish"
|
||||
dotnet publish -c "Release" -o obj/build-output/publish
|
||||
|
||||
cd obj/build-output/publish
|
||||
zip -r ${{ matrix.project_name }}.zip .
|
||||
mv ${{ matrix.project_name }}.zip ../../../
|
||||
|
||||
pwd
|
||||
ls -atlh ../../../
|
||||
|
||||
- name: Upload project artifact
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: ${{ matrix.project_name }}.zip
|
||||
path: ${{ matrix.base_path }}/${{ matrix.project_name }}/${{ matrix.project_name }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build-docker:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
security-events: write
|
||||
id-token: write
|
||||
needs:
|
||||
- build-artifacts
|
||||
if: ${{ needs.build-artifacts.outputs.has_secrets == 'true' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -149,6 +52,7 @@ jobs:
|
||||
- project_name: Admin
|
||||
base_path: ./src
|
||||
dotnet: true
|
||||
node: true
|
||||
- project_name: Api
|
||||
base_path: ./src
|
||||
dotnet: true
|
||||
@ -182,9 +86,6 @@ jobs:
|
||||
- project_name: Scim
|
||||
base_path: ./bitwarden_license/src
|
||||
dotnet: true
|
||||
- project_name: Server
|
||||
base_path: ./util
|
||||
dotnet: true
|
||||
- project_name: Setup
|
||||
base_path: ./util
|
||||
dotnet: true
|
||||
@ -192,6 +93,14 @@ jobs:
|
||||
base_path: ./bitwarden_license/src
|
||||
dotnet: true
|
||||
steps:
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
env:
|
||||
AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
@ -203,13 +112,67 @@ jobs:
|
||||
id: publish-branch-check
|
||||
run: |
|
||||
IFS="," read -a publish_branches <<< $PUBLISH_BRANCHES
|
||||
|
||||
if [[ " ${publish_branches[*]} " =~ " ${GITHUB_REF:11} " ]]; then
|
||||
echo "is_publish_branch=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "is_publish_branch=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
node-version: "16"
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
whoami
|
||||
dotnet --info
|
||||
node --version
|
||||
npm --version
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Build node
|
||||
if: ${{ matrix.node }}
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Publish project
|
||||
working-directory: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
if: ${{ matrix.dotnet }}
|
||||
run: |
|
||||
echo "Publish"
|
||||
dotnet publish -c "Release" -o obj/build-output/publish
|
||||
|
||||
cd obj/build-output/publish
|
||||
zip -r ${{ matrix.project_name }}.zip .
|
||||
mv ${{ matrix.project_name }}.zip ../../../
|
||||
|
||||
pwd
|
||||
ls -atlh ../../../
|
||||
|
||||
- name: Upload project artifact
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
if: ${{ matrix.dotnet }}
|
||||
with:
|
||||
name: ${{ matrix.project_name }}.zip
|
||||
path: ${{ matrix.base_path }}/${{ matrix.project_name }}/${{ matrix.project_name }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
########## Set up Docker ##########
|
||||
- name: Set up QEMU emulators
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
|
||||
########## ACRs ##########
|
||||
- name: Log in to Azure - production subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@ -277,26 +240,16 @@ jobs:
|
||||
fi
|
||||
echo "tags=$TAGS" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get build artifact
|
||||
if: ${{ matrix.dotnet }}
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: ${{ matrix.project_name }}.zip
|
||||
|
||||
- name: Set up build artifact
|
||||
if: ${{ matrix.dotnet }}
|
||||
run: |
|
||||
mkdir -p ${{ matrix.base_path}}/${{ matrix.project_name }}/obj/build-output/publish
|
||||
unzip ${{ matrix.project_name }}.zip \
|
||||
-d ${{ matrix.base_path }}/${{ matrix.project_name }}/obj/build-output/publish
|
||||
|
||||
- name: Build Docker image
|
||||
id: build-docker
|
||||
id: build-artifacts
|
||||
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0
|
||||
with:
|
||||
context: ${{ matrix.base_path }}/${{ matrix.project_name }}
|
||||
context: .
|
||||
file: ${{ matrix.base_path }}/${{ matrix.project_name }}/Dockerfile
|
||||
platforms: linux/amd64
|
||||
platforms: |
|
||||
linux/amd64,
|
||||
linux/arm/v7,
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.image-tags.outputs.tags }}
|
||||
secrets: |
|
||||
@ -309,7 +262,7 @@ jobs:
|
||||
- name: Sign image with Cosign
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
DIGEST: ${{ steps.build-docker.outputs.digest }}
|
||||
DIGEST: ${{ steps.build-artifacts.outputs.digest }}
|
||||
TAGS: ${{ steps.image-tags.outputs.tags }}
|
||||
run: |
|
||||
IFS="," read -a tags <<< "${TAGS}"
|
||||
@ -336,8 +289,8 @@ jobs:
|
||||
|
||||
upload:
|
||||
name: Upload
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-docker
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build-artifacts
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
@ -377,9 +330,9 @@ jobs:
|
||||
|
||||
# Run setup
|
||||
docker run -i --rm --name setup -v $STUB_OUTPUT/US:/bitwarden $SETUP_IMAGE \
|
||||
dotnet Setup.dll -stub 1 -install 1 -domain bitwarden.example.com -os lin -cloud-region US
|
||||
/app/Setup -stub 1 -install 1 -domain bitwarden.example.com -os lin -cloud-region US
|
||||
docker run -i --rm --name setup -v $STUB_OUTPUT/EU:/bitwarden $SETUP_IMAGE \
|
||||
dotnet Setup.dll -stub 1 -install 1 -domain bitwarden.example.com -os lin -cloud-region EU
|
||||
/app/Setup -stub 1 -install 1 -domain bitwarden.example.com -os lin -cloud-region EU
|
||||
|
||||
sudo chown -R $(whoami):$(whoami) $STUB_OUTPUT
|
||||
|
||||
@ -512,7 +465,7 @@ jobs:
|
||||
|
||||
build-mssqlmigratorutility:
|
||||
name: Build MSSQL migrator utility
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- lint
|
||||
defaults:
|
||||
@ -568,9 +521,9 @@ jobs:
|
||||
if: |
|
||||
github.event_name != 'pull_request'
|
||||
&& (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc')
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build-docker
|
||||
- build-artifacts
|
||||
steps:
|
||||
- name: Log in to Azure - CI subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@ -604,7 +557,7 @@ jobs:
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- build-docker
|
||||
- build-artifacts
|
||||
steps:
|
||||
- name: Log in to Azure - CI subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
@ -636,7 +589,8 @@ jobs:
|
||||
|
||||
setup-ephemeral-environment:
|
||||
name: Setup Ephemeral Environment
|
||||
needs: build-docker
|
||||
needs:
|
||||
- build-artifacts
|
||||
if: |
|
||||
needs.build-artifacts.outputs.has_secrets == 'true'
|
||||
&& github.event_name == 'pull_request'
|
||||
@ -644,8 +598,9 @@ jobs:
|
||||
uses: bitwarden/gh-actions/.github/workflows/_ephemeral_environment_manager.yml@main
|
||||
with:
|
||||
project: server
|
||||
pull_request_number: ${{ github.event.number }}
|
||||
pull_request_number: ${{ github.event.number || 0 }}
|
||||
secrets: inherit
|
||||
permissions: read-all
|
||||
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
@ -654,7 +609,6 @@ jobs:
|
||||
needs:
|
||||
- lint
|
||||
- build-artifacts
|
||||
- build-docker
|
||||
- upload
|
||||
- build-mssqlmigratorutility
|
||||
- self-host-build
|
||||
|
1
.github/workflows/code-references.yml
vendored
1
.github/workflows/code-references.yml
vendored
@ -44,6 +44,7 @@ jobs:
|
||||
with:
|
||||
accessToken: ${{ secrets.LD_ACCESS_TOKEN }}
|
||||
projKey: default
|
||||
allowTags: true
|
||||
|
||||
- name: Add label
|
||||
if: steps.collect.outputs.any-changed == 'true'
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
|
||||
<Version>2025.5.1</Version>
|
||||
<Version>2025.6.0</Version>
|
||||
|
||||
<RootNamespace>Bit.$(MSBuildProjectName)</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
@ -69,5 +69,4 @@
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
@ -5,9 +5,6 @@
|
||||
<a href="https://github.com/bitwarden/server/actions/workflows/build.yml?query=branch:main" target="_blank">
|
||||
<img src="https://github.com/bitwarden/server/actions/workflows/build.yml/badge.svg?branch=main" alt="Github Workflow build on main" />
|
||||
</a>
|
||||
<a href="https://hub.docker.com/u/bitwarden/" target="_blank">
|
||||
<img src="https://img.shields.io/docker/pulls/bitwarden/api.svg" alt="DockerHub" />
|
||||
</a>
|
||||
<a href="https://gitter.im/bitwarden/Lobby" target="_blank">
|
||||
<img src="https://badges.gitter.im/bitwarden/Lobby.svg" alt="gitter chat" />
|
||||
</a>
|
||||
@ -26,12 +23,12 @@ Please refer to the [Server Setup Guide](https://contributing.bitwarden.com/gett
|
||||
## Deploy
|
||||
|
||||
<p align="center">
|
||||
<a href="https://hub.docker.com/u/bitwarden/" target="_blank">
|
||||
<a href="https://github.com/orgs/bitwarden/packages" target="_blank">
|
||||
<img src="https://i.imgur.com/SZc8JnH.png" alt="docker" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
You can deploy Bitwarden using Docker containers on Windows, macOS, and Linux distributions. Use the provided PowerShell and Bash scripts to get started quickly. Find all of the Bitwarden images on [Docker Hub](https://hub.docker.com/u/bitwarden/).
|
||||
You can deploy Bitwarden using Docker containers on Windows, macOS, and Linux distributions. Use the provided PowerShell and Bash scripts to get started quickly. Find all of the Bitwarden images on [GitHub Container Registry](https://github.com/orgs/bitwarden/packages).
|
||||
|
||||
Full documentation for deploying Bitwarden with Docker can be found in our help center at: https://help.bitwarden.com/article/install-on-premise/
|
||||
|
||||
|
@ -3,9 +3,9 @@ using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Providers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
|
@ -7,6 +7,7 @@ using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
|
@ -5,12 +5,13 @@ using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Business.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -53,6 +54,7 @@ public class ProviderService : IProviderService
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly IProviderBillingService _providerBillingService;
|
||||
private readonly IPricingClient _pricingClient;
|
||||
private readonly IProviderClientOrganizationSignUpCommand _providerClientOrganizationSignUpCommand;
|
||||
|
||||
public ProviderService(IProviderRepository providerRepository, IProviderUserRepository providerUserRepository,
|
||||
IProviderOrganizationRepository providerOrganizationRepository, IUserRepository userRepository,
|
||||
@ -61,7 +63,8 @@ public class ProviderService : IProviderService
|
||||
IOrganizationRepository organizationRepository, GlobalSettings globalSettings,
|
||||
ICurrentContext currentContext, IStripeAdapter stripeAdapter, IFeatureService featureService,
|
||||
IDataProtectorTokenFactory<ProviderDeleteTokenable> providerDeleteTokenDataFactory,
|
||||
IApplicationCacheService applicationCacheService, IProviderBillingService providerBillingService, IPricingClient pricingClient)
|
||||
IApplicationCacheService applicationCacheService, IProviderBillingService providerBillingService, IPricingClient pricingClient,
|
||||
IProviderClientOrganizationSignUpCommand providerClientOrganizationSignUpCommand)
|
||||
{
|
||||
_providerRepository = providerRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
@ -81,6 +84,7 @@ public class ProviderService : IProviderService
|
||||
_applicationCacheService = applicationCacheService;
|
||||
_providerBillingService = providerBillingService;
|
||||
_pricingClient = pricingClient;
|
||||
_providerClientOrganizationSignUpCommand = providerClientOrganizationSignUpCommand;
|
||||
}
|
||||
|
||||
public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key, TaxInfo taxInfo, TokenizedPaymentSource tokenizedPaymentSource = null)
|
||||
@ -283,11 +287,10 @@ public class ProviderService : IProviderService
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
if (!keyedFilteredUsers.ContainsKey(user.Id))
|
||||
if (!keyedFilteredUsers.TryGetValue(user.Id, out var providerUser))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var providerUser = keyedFilteredUsers[user.Id];
|
||||
try
|
||||
{
|
||||
if (providerUser.Status != ProviderUserStatusType.Accepted || providerUser.ProviderId != providerId)
|
||||
@ -560,12 +563,12 @@ public class ProviderService : IProviderService
|
||||
|
||||
ThrowOnInvalidPlanType(provider.Type, organizationSignup.Plan);
|
||||
|
||||
var (organization, _, defaultCollection) = await _organizationService.SignupClientAsync(organizationSignup);
|
||||
var signUpResponse = await _providerClientOrganizationSignUpCommand.SignUpClientOrganizationAsync(organizationSignup);
|
||||
|
||||
var providerOrganization = new ProviderOrganization
|
||||
{
|
||||
ProviderId = providerId,
|
||||
OrganizationId = organization.Id,
|
||||
OrganizationId = signUpResponse.Organization.Id,
|
||||
Key = organizationSignup.OwnerKey,
|
||||
};
|
||||
|
||||
@ -574,12 +577,12 @@ public class ProviderService : IProviderService
|
||||
|
||||
// Give the owner Can Manage access over the default collection
|
||||
// The orgUser is not available when the org is created so we have to do it here as part of the invite
|
||||
var defaultOwnerAccess = defaultCollection != null
|
||||
var defaultOwnerAccess = signUpResponse.DefaultCollection != null
|
||||
?
|
||||
[
|
||||
new CollectionAccessSelection
|
||||
{
|
||||
Id = defaultCollection.Id,
|
||||
Id = signUpResponse.DefaultCollection.Id,
|
||||
HidePasswords = false,
|
||||
ReadOnly = false,
|
||||
Manage = true
|
||||
@ -587,7 +590,7 @@ public class ProviderService : IProviderService
|
||||
]
|
||||
: Array.Empty<CollectionAccessSelection>();
|
||||
|
||||
await _organizationService.InviteUsersAsync(organization.Id, user.Id, systemUser: null,
|
||||
await _organizationService.InviteUsersAsync(signUpResponse.Organization.Id, user.Id, systemUser: null,
|
||||
new (OrganizationUserInvite, string)[]
|
||||
{
|
||||
(
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System.Globalization;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
|
||||
namespace Bit.Commercial.Core.Billing.Models;
|
||||
namespace Bit.Commercial.Core.Billing.Providers.Models;
|
||||
|
||||
public class ProviderClientInvoiceReportRow
|
||||
{
|
@ -1,17 +1,17 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -24,9 +24,8 @@ using Microsoft.Extensions.Logging;
|
||||
using OneOf;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Commercial.Core.Billing;
|
||||
namespace Bit.Commercial.Core.Billing.Providers.Services;
|
||||
|
||||
[RequireFeature(FeatureFlagKeys.PM18770_EnableOrganizationBusinessUnitConversion)]
|
||||
public class BusinessUnitConverter(
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
GlobalSettings globalSettings,
|
@ -1,5 +1,5 @@
|
||||
using System.Globalization;
|
||||
using Bit.Commercial.Core.Billing.Models;
|
||||
using Bit.Commercial.Core.Billing.Providers.Models;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
@ -8,14 +8,15 @@ using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing;
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Models;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Contracts;
|
||||
using Bit.Core.Billing.Tax.Models;
|
||||
using Bit.Core.Billing.Tax.Services;
|
||||
using Bit.Core.Enums;
|
||||
@ -28,12 +29,11 @@ using Braintree;
|
||||
using CsvHelper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Stripe;
|
||||
|
||||
using static Bit.Core.Billing.Utilities;
|
||||
using Customer = Stripe.Customer;
|
||||
using Subscription = Stripe.Subscription;
|
||||
|
||||
namespace Bit.Commercial.Core.Billing;
|
||||
namespace Bit.Commercial.Core.Billing.Providers.Services;
|
||||
|
||||
public class ProviderBillingService(
|
||||
IBraintreeGateway braintreeGateway,
|
||||
@ -550,6 +550,15 @@ public class ProviderBillingService(
|
||||
[
|
||||
new CustomerTaxIdDataOptions { Type = taxIdType, Value = taxInfo.TaxIdNumber }
|
||||
];
|
||||
|
||||
if (taxIdType == StripeConstants.TaxIdType.SpanishNIF)
|
||||
{
|
||||
options.TaxIdData.Add(new CustomerTaxIdDataOptions
|
||||
{
|
||||
Type = StripeConstants.TaxIdType.EUVAT,
|
||||
Value = $"ES{taxInfo.TaxIdNumber}"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(provider.DiscountId))
|
@ -6,7 +6,7 @@ using Bit.Core.Billing;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Commercial.Core.Billing;
|
||||
namespace Bit.Commercial.Core.Billing.Providers.Services;
|
||||
|
||||
public static class ProviderPriceAdapter
|
||||
{
|
@ -1,9 +1,9 @@
|
||||
using Bit.Commercial.Core.AdminConsole.Providers;
|
||||
using Bit.Commercial.Core.AdminConsole.Services;
|
||||
using Bit.Commercial.Core.Billing;
|
||||
using Bit.Commercial.Core.Billing.Providers.Services;
|
||||
using Bit.Core.AdminConsole.Providers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Commercial.Core.Utilities;
|
||||
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!obj/build-output/publish/*
|
||||
!obj/Docker/empty/
|
||||
!entrypoint.sh
|
@ -1,6 +1,50 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
# We put the value in a file to be read by later layers.
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY . ./
|
||||
|
||||
# Restore project dependencies and tools
|
||||
WORKDIR /source/bitwarden_license/src/Scim
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Build project
|
||||
RUN . /tmp/rid.txt && dotnet publish \
|
||||
-c release \
|
||||
--no-restore \
|
||||
--self-contained \
|
||||
/p:PublishSingleFile=true \
|
||||
-r $RID \
|
||||
-o out
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
ENV SSL_CERT_DIR=/etc/bitwarden/ca-certificates
|
||||
EXPOSE 5000
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
@ -9,11 +53,10 @@ RUN apt-get update \
|
||||
krb5-user \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ASPNETCORE_URLS http://+:5000
|
||||
# Copy app from the build stage
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
COPY obj/build-output/publish .
|
||||
COPY entrypoint.sh /
|
||||
COPY --from=build /source/bitwarden_license/src/Scim/out /app
|
||||
COPY ./bitwarden_license/src/Scim/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1
|
||||
|
@ -16,8 +16,8 @@ public class Program
|
||||
{
|
||||
var context = e.Properties["SourceContext"].ToString();
|
||||
|
||||
if (e.Properties.ContainsKey("RequestPath") &&
|
||||
!string.IsNullOrWhiteSpace(e.Properties["RequestPath"]?.ToString()) &&
|
||||
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
|
||||
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
|
||||
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
|
||||
{
|
||||
return false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Setup
|
||||
|
||||
@ -19,31 +19,42 @@ then
|
||||
LGID=65534
|
||||
fi
|
||||
|
||||
# Create user and group
|
||||
if [ "$(id -u)" = "0" ]
|
||||
then
|
||||
# Create user and group
|
||||
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
|
||||
# The rest...
|
||||
# The rest...
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
fi
|
||||
|
||||
gosu_cmd="gosu $USERNAME:$GROUPNAME"
|
||||
else
|
||||
gosu_cmd=""
|
||||
fi
|
||||
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
gosu $USERNAME:$GROUPNAME kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
$gosu_cmd kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Scim.dll
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
if [[ -z $globalSettings__identityServer__certificateLocation ]]; then
|
||||
export globalSettings__identityServer__certificateLocation=/etc/bitwarden/identity/identity.pfx
|
||||
fi
|
||||
fi
|
||||
|
||||
exec $gosu_cmd /app/Scim
|
||||
|
@ -370,8 +370,8 @@ public class AccountController : Controller
|
||||
// for the user identifier.
|
||||
static bool nameIdIsNotTransient(Claim c) => c.Type == ClaimTypes.NameIdentifier
|
||||
&& (c.Properties == null
|
||||
|| !c.Properties.ContainsKey(SamlPropertyKeys.ClaimFormat)
|
||||
|| c.Properties[SamlPropertyKeys.ClaimFormat] != SamlNameIdFormats.Transient);
|
||||
|| !c.Properties.TryGetValue(SamlPropertyKeys.ClaimFormat, out var claimFormat)
|
||||
|| claimFormat != SamlNameIdFormats.Transient);
|
||||
|
||||
// Try to determine the unique id of the external user (issued by the provider)
|
||||
// the most common claim type for that are the sub claim and the NameIdentifier
|
||||
|
@ -1,6 +1,50 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
# We put the value in a file to be read by later layers.
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY . ./
|
||||
|
||||
# Restore project dependencies and tools
|
||||
WORKDIR /source/bitwarden_license/src/Sso
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Build project
|
||||
RUN . /tmp/rid.txt && dotnet publish \
|
||||
-c release \
|
||||
--no-restore \
|
||||
--self-contained \
|
||||
/p:PublishSingleFile=true \
|
||||
-r $RID \
|
||||
-o out
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
ENV SSL_CERT_DIR=/etc/bitwarden/ca-certificates
|
||||
EXPOSE 5000
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
@ -9,11 +53,10 @@ RUN apt-get update \
|
||||
krb5-user \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ASPNETCORE_URLS http://+:5000
|
||||
# Copy app from the build stage
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
COPY obj/build-output/publish .
|
||||
COPY entrypoint.sh /
|
||||
COPY --from=build /source/bitwarden_license/src/Sso/out /app
|
||||
COPY ./bitwarden_license/src/Sso/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1
|
||||
|
@ -17,8 +17,8 @@ public class Program
|
||||
logging.AddSerilog(hostingContext, (e, globalSettings) =>
|
||||
{
|
||||
var context = e.Properties["SourceContext"].ToString();
|
||||
if (e.Properties.ContainsKey("RequestPath") &&
|
||||
!string.IsNullOrWhiteSpace(e.Properties["RequestPath"]?.ToString()) &&
|
||||
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
|
||||
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
|
||||
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
|
||||
{
|
||||
return false;
|
||||
|
@ -46,9 +46,9 @@ public static class OpenIdConnectOptionsExtensions
|
||||
|
||||
// Handle State if we've gotten that back
|
||||
var decodedState = options.StateDataFormat.Unprotect(state);
|
||||
if (decodedState != null && decodedState.Items.ContainsKey("scheme"))
|
||||
if (decodedState != null && decodedState.Items.TryGetValue("scheme", out var stateScheme))
|
||||
{
|
||||
return decodedState.Items["scheme"] == scheme;
|
||||
return stateScheme == scheme;
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Setup
|
||||
|
||||
@ -19,37 +19,42 @@ then
|
||||
LGID=65534
|
||||
fi
|
||||
|
||||
# Create user and group
|
||||
if [ "$(id -u)" = "0" ]
|
||||
then
|
||||
# Create user and group
|
||||
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
|
||||
# The rest...
|
||||
# The rest...
|
||||
|
||||
mkdir -p /etc/bitwarden/identity
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/identity/identity.pfx /app/identity.pfx
|
||||
fi
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
fi
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
gosu_cmd="gosu $USERNAME:$GROUPNAME"
|
||||
else
|
||||
gosu_cmd=""
|
||||
fi
|
||||
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
gosu $USERNAME:$GROUPNAME kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
$gosu_cmd kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Sso.dll
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
if [[ -z $globalSettings__identityServer__certificateLocation ]]; then
|
||||
export globalSettings__identityServer__certificateLocation=/etc/bitwarden/identity/identity.pfx
|
||||
fi
|
||||
fi
|
||||
|
||||
exec $gosu_cmd /app/Sso
|
||||
|
199
bitwarden_license/src/Sso/package-lock.json
generated
199
bitwarden_license/src/Sso/package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "-",
|
||||
"dependencies": {
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap": "5.3.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.7.1"
|
||||
},
|
||||
@ -17,9 +17,9 @@
|
||||
"css-loader": "7.1.2",
|
||||
"expose-loader": "5.0.1",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"sass": "1.85.0",
|
||||
"sass-loader": "16.0.4",
|
||||
"webpack": "5.97.1",
|
||||
"sass": "1.88.0",
|
||||
"sass-loader": "16.0.5",
|
||||
"webpack": "5.99.8",
|
||||
"webpack-cli": "5.1.4"
|
||||
}
|
||||
},
|
||||
@ -455,13 +455,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
|
||||
"integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
|
||||
"version": "22.15.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
|
||||
"integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
@ -748,9 +748,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
||||
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.6.tgz",
|
||||
"integrity": "sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -781,9 +781,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.24.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
||||
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
|
||||
"version": "4.24.5",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz",
|
||||
"integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -801,10 +801,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001688",
|
||||
"electron-to-chromium": "^1.5.73",
|
||||
"caniuse-lite": "^1.0.30001716",
|
||||
"electron-to-chromium": "^1.5.149",
|
||||
"node-releases": "^2.0.19",
|
||||
"update-browserslist-db": "^1.1.1"
|
||||
"update-browserslist-db": "^1.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@ -821,9 +821,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001707",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz",
|
||||
"integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==",
|
||||
"version": "1.0.30001718",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz",
|
||||
"integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -975,9 +975,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.128",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz",
|
||||
"integrity": "sha512-bo1A4HH/NS522Ws0QNFIzyPcyUUNV/yyy70Ho1xqfGYzPUme2F/xr4tlEOuM6/A538U1vDA7a4XfCd1CKRegKQ==",
|
||||
"version": "1.5.155",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz",
|
||||
"integrity": "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@ -1009,9 +1009,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
|
||||
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
||||
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -1106,13 +1106,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
|
||||
@ -1248,9 +1241,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz",
|
||||
"integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz",
|
||||
"integrity": "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -1754,16 +1747,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -1877,9 +1860,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.85.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz",
|
||||
"integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
|
||||
"version": "1.88.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.88.0.tgz",
|
||||
"integrity": "sha512-sF6TWQqjFvr4JILXzG4ucGOLELkESHL+I5QJhh7CNaE+Yge0SI+ehCatsXhJ7ymU1hAFcIS3/PBpjdIbXoyVbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1898,9 +1881,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass-loader": {
|
||||
"version": "16.0.4",
|
||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.4.tgz",
|
||||
"integrity": "sha512-LavLbgbBGUt3wCiYzhuLLu65+fWXaXLmq7YxivLhEqmiupCFZ5sKUAipK3do6V80YSU0jvSxNhEdT13IXNr3rg==",
|
||||
"version": "16.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz",
|
||||
"integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1939,9 +1922,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/schema-utils": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
|
||||
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
|
||||
"integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1959,9 +1942,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
@ -2078,9 +2061,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
|
||||
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -2088,14 +2071,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.39.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
|
||||
"integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
|
||||
"version": "5.39.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.2.tgz",
|
||||
"integrity": "sha512-yEPUmWve+VA78bI71BW70Dh0TuV4HHd+I5SHOAfS1+QBOmvmCiiffgjR8ryyEd3KIfvPGFqoADt8LdQ6XpXIvg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
"acorn": "^8.14.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
@ -2156,9 +2139,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -2193,16 +2176,6 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
@ -2211,9 +2184,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
|
||||
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -2225,14 +2198,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.97.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
|
||||
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
|
||||
"version": "5.99.8",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz",
|
||||
"integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.6",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@webassemblyjs/ast": "^1.14.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.14.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.14.1",
|
||||
@ -2249,9 +2223,9 @@
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.2.0",
|
||||
"schema-utils": "^4.3.2",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
@ -2352,59 +2326,6 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webpack/node_modules/schema-utils": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
|
||||
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"build": "webpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap": "5.3.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.7.1"
|
||||
},
|
||||
@ -16,9 +16,9 @@
|
||||
"css-loader": "7.1.2",
|
||||
"expose-loader": "5.0.1",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"sass": "1.85.0",
|
||||
"sass-loader": "16.0.4",
|
||||
"webpack": "5.97.1",
|
||||
"sass": "1.88.0",
|
||||
"sass-loader": "16.0.5",
|
||||
"webpack": "5.99.8",
|
||||
"webpack-cli": "5.1.4"
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
|
@ -6,11 +6,12 @@ using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Business.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -717,8 +718,8 @@ public class ProviderServiceTests
|
||||
|
||||
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||
sutProvider.GetDependency<IOrganizationService>().SignupClientAsync(organizationSignup)
|
||||
.Returns((organization, null as OrganizationUser, new Collection()));
|
||||
sutProvider.GetDependency<IProviderClientOrganizationSignUpCommand>().SignUpClientOrganizationAsync(organizationSignup)
|
||||
.Returns(new ProviderClientOrganizationSignUpResponse(organization, new Collection()));
|
||||
|
||||
var providerOrganization =
|
||||
await sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, clientOwnerEmail, user);
|
||||
@ -755,8 +756,8 @@ public class ProviderServiceTests
|
||||
|
||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||
|
||||
sutProvider.GetDependency<IOrganizationService>().SignupClientAsync(organizationSignup)
|
||||
.Returns((organization, null as OrganizationUser, new Collection()));
|
||||
sutProvider.GetDependency<IProviderClientOrganizationSignUpCommand>().SignUpClientOrganizationAsync(organizationSignup)
|
||||
.Returns(new ProviderClientOrganizationSignUpResponse(organization, new Collection()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, clientOwnerEmail, user));
|
||||
@ -782,8 +783,8 @@ public class ProviderServiceTests
|
||||
|
||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||
|
||||
sutProvider.GetDependency<IOrganizationService>().SignupClientAsync(organizationSignup)
|
||||
.Returns((organization, null as OrganizationUser, new Collection()));
|
||||
sutProvider.GetDependency<IProviderClientOrganizationSignUpCommand>().SignUpClientOrganizationAsync(organizationSignup)
|
||||
.Returns(new ProviderClientOrganizationSignUpResponse(organization, new Collection()));
|
||||
|
||||
var providerOrganization = await sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, clientOwnerEmail, user);
|
||||
|
||||
@ -821,8 +822,8 @@ public class ProviderServiceTests
|
||||
|
||||
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||
sutProvider.GetDependency<IOrganizationService>().SignupClientAsync(organizationSignup)
|
||||
.Returns((organization, null as OrganizationUser, defaultCollection));
|
||||
sutProvider.GetDependency<IProviderClientOrganizationSignUpCommand>().SignUpClientOrganizationAsync(organizationSignup)
|
||||
.Returns(new ProviderClientOrganizationSignUpResponse(organization, defaultCollection));
|
||||
|
||||
var providerOrganization =
|
||||
await sutProvider.Sut.CreateOrganizationAsync(provider.Id, organizationSignup, clientOwnerEmail, user);
|
||||
|
@ -1,16 +1,16 @@
|
||||
#nullable enable
|
||||
using System.Text;
|
||||
using Bit.Commercial.Core.Billing;
|
||||
using Bit.Commercial.Core.Billing.Providers.Services;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -25,7 +25,7 @@ using NSubstitute;
|
||||
using Stripe;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Commercial.Core.Test.Billing;
|
||||
namespace Bit.Commercial.Core.Test.Billing.Providers;
|
||||
|
||||
public class BusinessUnitConverterTests
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using Bit.Commercial.Core.Billing;
|
||||
using Bit.Commercial.Core.Billing.Models;
|
||||
using Bit.Commercial.Core.Billing.Providers.Models;
|
||||
using Bit.Commercial.Core.Billing.Providers.Services;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
@ -10,13 +10,13 @@ using Bit.Core.AdminConsole.Models.Data.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Models;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Contracts;
|
||||
using Bit.Core.Billing.Tax.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -40,7 +40,7 @@ using Customer = Stripe.Customer;
|
||||
using PaymentMethod = Stripe.PaymentMethod;
|
||||
using Subscription = Stripe.Subscription;
|
||||
|
||||
namespace Bit.Commercial.Core.Test.Billing;
|
||||
namespace Bit.Commercial.Core.Test.Billing.Providers;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class ProviderBillingServiceTests
|
@ -1,11 +1,11 @@
|
||||
using Bit.Commercial.Core.Billing;
|
||||
using Bit.Commercial.Core.Billing.Providers.Services;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Stripe;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Commercial.Core.Test.Billing;
|
||||
namespace Bit.Commercial.Core.Test.Billing.Providers;
|
||||
|
||||
public class ProviderPriceAdapterTests
|
||||
{
|
@ -3,7 +3,7 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Commercial.Core.Test.Billing;
|
||||
namespace Bit.Commercial.Core.Test.Billing.Tax;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class TaxServiceTests
|
@ -99,7 +99,7 @@ services:
|
||||
- idp
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq:management
|
||||
image: rabbitmq:4.1.0-management
|
||||
container_name: rabbitmq
|
||||
ports:
|
||||
- "5672:5672"
|
||||
@ -108,7 +108,7 @@ services:
|
||||
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
|
||||
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
|
||||
volumes:
|
||||
- rabbitmq_data:/var/lib/rabbitmq_data
|
||||
- rabbitmq_data:/var/lib/rabbitmq
|
||||
profiles:
|
||||
- rabbitmq
|
||||
|
||||
|
@ -33,6 +33,39 @@
|
||||
"Name": "events-webhook-subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "event-integrations",
|
||||
"Subscriptions": [
|
||||
{
|
||||
"Name": "integration-slack-subscription",
|
||||
"Rules": [
|
||||
{
|
||||
"Name": "slack-integration-filter",
|
||||
"Properties": {
|
||||
"FilterType": "Correlation",
|
||||
"CorrelationFilter": {
|
||||
"Label": "slack"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "integration-webhook-subscription",
|
||||
"Rules": [
|
||||
{
|
||||
"Name": "webhook-integration-filter",
|
||||
"Properties": {
|
||||
"FilterType": "Correlation",
|
||||
"CorrelationFilter": {
|
||||
"Label": "webhook"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ $corsRules = (@{
|
||||
AllowedMethods = @("Get", "PUT");
|
||||
});
|
||||
$containers = "attachments", "sendfiles", "misc";
|
||||
$queues = "event", "notifications", "reference-events", "mail";
|
||||
$queues = "event", "notifications", "mail";
|
||||
$tables = "event", "metadata", "installationdevice";
|
||||
# End configuration
|
||||
|
||||
|
@ -5,6 +5,6 @@
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.Build.Traversal": "4.1.0",
|
||||
"Microsoft.Build.Sql": "0.1.9-preview"
|
||||
"Microsoft.Build.Sql": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!obj/build-output/publish/*
|
||||
!obj/Docker/empty/
|
||||
!entrypoint.sh
|
@ -11,8 +11,7 @@ using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
|
||||
@ -20,9 +19,6 @@ using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -45,12 +41,9 @@ public class OrganizationsController : Controller
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly ILogger<OrganizationsController> _logger;
|
||||
private readonly IAccessControlService _accessControlService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly ISecretRepository _secretRepository;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||
@ -73,12 +66,9 @@ public class OrganizationsController : Controller
|
||||
IPaymentService paymentService,
|
||||
IApplicationCacheService applicationCacheService,
|
||||
GlobalSettings globalSettings,
|
||||
IReferenceEventService referenceEventService,
|
||||
IUserService userService,
|
||||
IProviderRepository providerRepository,
|
||||
ILogger<OrganizationsController> logger,
|
||||
IAccessControlService accessControlService,
|
||||
ICurrentContext currentContext,
|
||||
ISecretRepository secretRepository,
|
||||
IProjectRepository projectRepository,
|
||||
IServiceAccountRepository serviceAccountRepository,
|
||||
@ -100,12 +90,9 @@ public class OrganizationsController : Controller
|
||||
_paymentService = paymentService;
|
||||
_applicationCacheService = applicationCacheService;
|
||||
_globalSettings = globalSettings;
|
||||
_referenceEventService = referenceEventService;
|
||||
_userService = userService;
|
||||
_providerRepository = providerRepository;
|
||||
_logger = logger;
|
||||
_accessControlService = accessControlService;
|
||||
_currentContext = currentContext;
|
||||
_secretRepository = secretRepository;
|
||||
_projectRepository = projectRepository;
|
||||
_serviceAccountRepository = serviceAccountRepository;
|
||||
@ -255,10 +242,32 @@ public class OrganizationsController : Controller
|
||||
Seats = organization.Seats
|
||||
};
|
||||
|
||||
if (model.PlanType.HasValue)
|
||||
{
|
||||
var freePlan = await _pricingClient.GetPlanOrThrow(model.PlanType.Value);
|
||||
var isDowngradingToFree = organization.PlanType != PlanType.Free && model.PlanType.Value == PlanType.Free;
|
||||
if (isDowngradingToFree)
|
||||
{
|
||||
if (model.Seats.HasValue && model.Seats.Value > freePlan.PasswordManager.MaxSeats)
|
||||
{
|
||||
TempData["Error"] = $"Organizations with more than {freePlan.PasswordManager.MaxSeats} seats cannot be downgraded to the Free plan";
|
||||
return RedirectToAction("Edit", new { id });
|
||||
}
|
||||
|
||||
if (model.MaxCollections > freePlan.PasswordManager.MaxCollections)
|
||||
{
|
||||
TempData["Error"] = $"Organizations with more than {freePlan.PasswordManager.MaxCollections} collections cannot be downgraded to the Free plan. Your organization currently has {organization.MaxCollections} collections.";
|
||||
return RedirectToAction("Edit", new { id });
|
||||
}
|
||||
|
||||
model.MaxStorageGb = null;
|
||||
model.ExpirationDate = null;
|
||||
model.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateOrganization(organization, model);
|
||||
|
||||
var plan = await _pricingClient.GetPlanOrThrow(organization.PlanType);
|
||||
|
||||
if (organization.UseSecretsManager && !plan.SupportsSecretsManager)
|
||||
{
|
||||
TempData["Error"] = "Plan does not support Secrets Manager";
|
||||
@ -272,11 +281,6 @@ public class OrganizationsController : Controller
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
|
||||
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.OrganizationEditedByAdmin, organization, _currentContext)
|
||||
{
|
||||
EventRaisedByUser = _userService.GetUserName(User),
|
||||
SalesAssistedTrialStarted = model.SalesAssistedTrialStarted,
|
||||
});
|
||||
|
||||
return RedirectToAction("Edit", new { id });
|
||||
}
|
||||
|
@ -10,13 +10,13 @@ using Bit.Core.AdminConsole.Providers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Contracts;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Models;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
|
@ -44,6 +44,8 @@ public class OrganizationViewModel
|
||||
orgUsers
|
||||
.Where(u => u.Type == OrganizationUserType.Admin && u.Status == organizationUserStatus)
|
||||
.Select(u => u.Email));
|
||||
OwnersDetails = orgUsers.Where(u => u.Type == OrganizationUserType.Owner && u.Status == organizationUserStatus);
|
||||
AdminsDetails = orgUsers.Where(u => u.Type == OrganizationUserType.Admin && u.Status == organizationUserStatus);
|
||||
SecretsCount = secretsCount;
|
||||
ProjectsCount = projectCount;
|
||||
ServiceAccountsCount = serviceAccountsCount;
|
||||
@ -70,4 +72,6 @@ public class OrganizationViewModel
|
||||
public int OccupiedSmSeatsCount { get; set; }
|
||||
public bool UseSecretsManager => Organization.UseSecretsManager;
|
||||
public bool UseRiskInsights => Organization.UseRiskInsights;
|
||||
public IEnumerable<OrganizationUserUserDetails> OwnersDetails { get; set; }
|
||||
public IEnumerable<OrganizationUserUserDetails> AdminsDetails { get; set; }
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Data.Provider;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.SharedWeb.Utilities;
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Data.Provider;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
|
||||
namespace Bit.Admin.AdminConsole.Models;
|
||||
|
||||
@ -19,7 +19,7 @@ public class ProviderViewModel
|
||||
{
|
||||
Provider = provider;
|
||||
UserCount = providerUsers.Count();
|
||||
ProviderAdmins = providerUsers.Where(u => u.Type == ProviderUserType.ProviderAdmin);
|
||||
ProviderUsers = providerUsers;
|
||||
ProviderOrganizations = organizations.Where(o => o.ProviderId == provider.Id);
|
||||
|
||||
if (Provider.Type == ProviderType.Msp)
|
||||
@ -61,7 +61,7 @@ public class ProviderViewModel
|
||||
|
||||
public int UserCount { get; set; }
|
||||
public Provider Provider { get; set; }
|
||||
public IEnumerable<ProviderUserUserDetails> ProviderAdmins { get; set; }
|
||||
public IEnumerable<ProviderUserUserDetails> ProviderUsers { get; set; }
|
||||
public IEnumerable<ProviderOrganizationOrganizationDetails> ProviderOrganizations { get; set; }
|
||||
public List<ProviderPlanViewModel> ProviderPlanViewModels { get; set; } = [];
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
@using Bit.Admin.Enums;
|
||||
@using Bit.Admin.Models
|
||||
@using Bit.Core
|
||||
@using Bit.Core.AdminConsole.Enums.Provider
|
||||
@using Bit.Core.Billing.Enums
|
||||
@using Bit.Core.Billing.Extensions
|
||||
@using Bit.Core.Services
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject Bit.Admin.Services.IAccessControlService AccessControlService
|
||||
@inject IFeatureService FeatureService
|
||||
@model OrganizationEditModel
|
||||
@{
|
||||
ViewData["Title"] = (Model.Provider != null ? "Client " : string.Empty) + "Organization: " + Model.Name;
|
||||
@ -19,12 +15,10 @@
|
||||
var canDelete = AccessControlService.UserHasPermission(Permission.Org_Delete);
|
||||
var canUnlinkFromProvider = AccessControlService.UserHasPermission(Permission.Provider_Edit);
|
||||
|
||||
var canConvertToBusinessUnit =
|
||||
FeatureService.IsEnabled(FeatureFlagKeys.PM18770_EnableOrganizationBusinessUnitConversion) &&
|
||||
AccessControlService.UserHasPermission(Permission.Org_Billing_ConvertToBusinessUnit) &&
|
||||
Model.Organization.PlanType.GetProductTier() == ProductTierType.Enterprise &&
|
||||
!string.IsNullOrEmpty(Model.Organization.GatewaySubscriptionId) &&
|
||||
Model.Provider is null or { Type: ProviderType.BusinessUnit, Status: ProviderStatusType.Pending };
|
||||
var canConvertToBusinessUnit = AccessControlService.UserHasPermission(Permission.Org_Billing_ConvertToBusinessUnit) &&
|
||||
Model.Organization.PlanType.GetProductTier() == ProductTierType.Enterprise &&
|
||||
!string.IsNullOrEmpty(Model.Organization.GatewaySubscriptionId) &&
|
||||
Model.Provider is null or { Type: ProviderType.BusinessUnit, Status: ProviderStatusType.Pending };
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
|
@ -19,12 +19,6 @@
|
||||
<span id="org-confirmed-users" title="Confirmed">@Model.UserConfirmedCount</span>)
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Owners</dt>
|
||||
<dd id="org-owner" class="col-sm-8 col-lg-9">@(string.IsNullOrWhiteSpace(Model.Owners) ? "None" : Model.Owners)</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Admins</dt>
|
||||
<dd id="org-admins" class="col-sm-8 col-lg-9">@(string.IsNullOrWhiteSpace(Model.Admins) ? "None" : Model.Admins)</dd>
|
||||
|
||||
<dt class="col-sm-4 col-lg-3">Using 2FA</dt>
|
||||
<dd id="org-2fa" class="col-sm-8 col-lg-9">@(Model.Organization.TwoFactorIsEnabled() ? "Yes" : "No")</dd>
|
||||
|
||||
@ -76,3 +70,49 @@
|
||||
<dt class="col-sm-4 col-lg-3">Secrets Manager Seats</dt>
|
||||
<dd id="sm-seat-count" class="col-sm-8 col-lg-9">@(Model.UseSecretsManager ? Model.OccupiedSmSeatsCount: "N/A" )</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Administrators</h2>
|
||||
<dl class="row">
|
||||
<div class="table-responsive">
|
||||
<div class="col-8">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 190px;">Email</th>
|
||||
<th style="width: 60px;">Role</th>
|
||||
<th style="width: 40px;">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if(!Model.Admins.Any() && !Model.Owners.Any())
|
||||
{
|
||||
<tr>
|
||||
<td colspan="6">No results to list.</td>
|
||||
</tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach(var owner in Model.OwnersDetails)
|
||||
{
|
||||
<tr>
|
||||
<td class="align-middle">@owner.Email</td>
|
||||
<td class="align-middle">Owner</td>
|
||||
<td class="align-middle">@owner.Status</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@foreach(var admin in Model.AdminsDetails)
|
||||
{
|
||||
<tr>
|
||||
<td class="align-middle">@admin.Email</td>
|
||||
<td class="align-middle">Admin</td>
|
||||
<td class="align-middle">@admin.Status</td>
|
||||
</tr>
|
||||
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
|
@ -7,7 +7,7 @@
|
||||
var canResendEmailInvite = AccessControlService.UserHasPermission(Permission.Provider_ResendEmailInvite);
|
||||
}
|
||||
|
||||
<h2>Provider Admins</h2>
|
||||
<h2>Administrators</h2>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<div class="table-responsive">
|
||||
@ -15,12 +15,13 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 190px;">Email</th>
|
||||
<th style="width: 160px;">Role</th>
|
||||
<th style="width: 40px;">Status</th>
|
||||
<th style="width: 30px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if(!Model.ProviderAdmins.Any())
|
||||
@if(!Model.ProviderUsers.Any())
|
||||
{
|
||||
<tr>
|
||||
<td colspan="6">No results to list.</td>
|
||||
@ -28,29 +29,39 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach(var admin in Model.ProviderAdmins)
|
||||
@foreach(var user in Model.ProviderUsers)
|
||||
{
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
@admin.Email
|
||||
@user.Email
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
@admin.Status
|
||||
@if(@user.Type == 0)
|
||||
{
|
||||
<span>Provider Admin</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Service User</span>
|
||||
}
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
@user.Status
|
||||
</td>
|
||||
<td>
|
||||
@if(admin.Status.Equals(ProviderUserStatusType.Confirmed)
|
||||
@if(user.Status.Equals(ProviderUserStatusType.Confirmed)
|
||||
&& @Model.Provider.Status.Equals(ProviderStatusType.Pending)
|
||||
&& canResendEmailInvite)
|
||||
{
|
||||
@if(@TempData["InviteResentTo"] != null && @TempData["InviteResentTo"].ToString() == @admin.UserId.Value.ToString())
|
||||
@if(@TempData["InviteResentTo"] != null && @TempData["InviteResentTo"].ToString() == @user.UserId.Value.ToString())
|
||||
{
|
||||
<button class="btn btn-outline-success btn-sm disabled" disabled>Invite Resent!</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a class="btn btn-outline-secondary btn-sm"
|
||||
data-id="@admin.Id" asp-controller="Providers"
|
||||
asp-action="ResendInvite" asp-route-ownerId="@admin.UserId"
|
||||
data-id="@user.Id" asp-controller="Providers"
|
||||
asp-action="ResendInvite" asp-route-ownerId="@user.UserId"
|
||||
asp-route-providerId="@Model.Provider.Id">
|
||||
Resend Setup Invite
|
||||
</a>
|
||||
|
@ -2,12 +2,11 @@
|
||||
using Bit.Admin.Billing.Models;
|
||||
using Bit.Admin.Enums;
|
||||
using Bit.Admin.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
@ -18,7 +17,6 @@ namespace Bit.Admin.Billing.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[Route("organizations/billing/{organizationId:guid}/business-unit")]
|
||||
[RequireFeature(FeatureFlagKeys.PM18770_EnableOrganizationBusinessUnitConversion)]
|
||||
public class BusinessUnitConversionController(
|
||||
IBusinessUnitConverter businessUnitConverter,
|
||||
IOrganizationRepository organizationRepository,
|
||||
|
@ -1,8 +1,8 @@
|
||||
using Bit.Admin.Billing.Models;
|
||||
using Bit.Admin.Enums;
|
||||
using Bit.Admin.Utilities;
|
||||
using Bit.Core.Billing.Migration.Models;
|
||||
using Bit.Core.Billing.Migration.Services;
|
||||
using Bit.Core.Billing.Providers.Migration.Models;
|
||||
using Bit.Core.Billing.Providers.Migration.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
|
||||
namespace Bit.Admin.Billing.Models;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
@using System.Text.Json
|
||||
@model Bit.Core.Billing.Migration.Models.ProviderMigrationResult
|
||||
@model Bit.Core.Billing.Providers.Migration.Models.ProviderMigrationResult
|
||||
@{
|
||||
ViewData["Title"] = "Results";
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model Bit.Core.Billing.Migration.Models.ProviderMigrationResult[]
|
||||
@model Bit.Core.Billing.Providers.Migration.Models.ProviderMigrationResult[]
|
||||
@{
|
||||
ViewData["Title"] = "Results";
|
||||
}
|
||||
|
@ -1,21 +1,71 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Set up Node
|
||||
ARG NODE_VERSION=20
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g npm@latest && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY . ./
|
||||
|
||||
# Restore project dependencies and tools
|
||||
WORKDIR /source/src/Admin
|
||||
RUN npm ci
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Build project
|
||||
RUN npm run build
|
||||
RUN . /tmp/rid.txt && dotnet publish \
|
||||
-c release \
|
||||
--no-restore \
|
||||
--self-contained \
|
||||
/p:PublishSingleFile=true \
|
||||
-r $RID \
|
||||
-o out
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
ENV SSL_CERT_DIR=/etc/bitwarden/ca-certificates
|
||||
EXPOSE 5000
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gosu \
|
||||
curl \
|
||||
krb5-user \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ASPNETCORE_URLS http://+:5000
|
||||
# Copy app from the build stage
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
COPY obj/build-output/publish .
|
||||
COPY entrypoint.sh /
|
||||
COPY --from=build /source/src/Admin/out /app
|
||||
COPY ./src/Admin/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000 || exit 1
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
@ -39,7 +39,7 @@ public class ReadOnlyEnvIdentityUserStore : ReadOnlyIdentityUserStore
|
||||
}
|
||||
}
|
||||
|
||||
var userStamp = usersDict.ContainsKey(normalizedEmail) ? usersDict[normalizedEmail] : null;
|
||||
var userStamp = usersDict.GetValueOrDefault(normalizedEmail);
|
||||
if (userStamp == null)
|
||||
{
|
||||
return Task.FromResult<IdentityUser>(null);
|
||||
|
@ -20,8 +20,8 @@ public class Program
|
||||
logging.AddSerilog(hostingContext, (e, globalSettings) =>
|
||||
{
|
||||
var context = e.Properties["SourceContext"].ToString();
|
||||
if (e.Properties.ContainsKey("RequestPath") &&
|
||||
!string.IsNullOrWhiteSpace(e.Properties["RequestPath"]?.ToString()) &&
|
||||
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
|
||||
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
|
||||
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
|
||||
{
|
||||
return false;
|
||||
|
@ -29,12 +29,12 @@ public class AccessControlService : IAccessControlService
|
||||
}
|
||||
|
||||
var userRole = GetUserRoleFromClaim();
|
||||
if (string.IsNullOrEmpty(userRole) || !RolePermissionMapping.RolePermissions.ContainsKey(userRole))
|
||||
if (string.IsNullOrEmpty(userRole) || !RolePermissionMapping.RolePermissions.TryGetValue(userRole, out var rolePermissions))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return RolePermissionMapping.RolePermissions[userRole].Contains(permission);
|
||||
return rolePermissions.Contains(permission);
|
||||
}
|
||||
|
||||
public string GetUserRole(string userEmail)
|
||||
|
@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Bit.Admin.Services;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Migration;
|
||||
using Bit.Core.Billing.Providers.Migration;
|
||||
|
||||
#if !OSS
|
||||
using Bit.Commercial.Core.Utilities;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Setup
|
||||
|
||||
@ -19,31 +19,36 @@ then
|
||||
LGID=65534
|
||||
fi
|
||||
|
||||
# Create user and group
|
||||
if [ "$(id -u)" = "0" ]
|
||||
then
|
||||
# Create user and group
|
||||
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
|
||||
# The rest...
|
||||
# The rest...
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
fi
|
||||
|
||||
gosu_cmd="gosu $USERNAME:$GROUPNAME"
|
||||
else
|
||||
gosu_cmd=""
|
||||
fi
|
||||
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
gosu $USERNAME:$GROUPNAME kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
$gosu_cmd kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Admin.dll
|
||||
exec $gosu_cmd /app/Admin
|
||||
|
199
src/Admin/package-lock.json
generated
199
src/Admin/package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap": "5.3.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.7.1",
|
||||
"toastr": "2.1.4"
|
||||
@ -18,9 +18,9 @@
|
||||
"css-loader": "7.1.2",
|
||||
"expose-loader": "5.0.1",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"sass": "1.85.0",
|
||||
"sass-loader": "16.0.4",
|
||||
"webpack": "5.97.1",
|
||||
"sass": "1.88.0",
|
||||
"sass-loader": "16.0.5",
|
||||
"webpack": "5.99.8",
|
||||
"webpack-cli": "5.1.4"
|
||||
}
|
||||
},
|
||||
@ -456,13 +456,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
|
||||
"integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
|
||||
"version": "22.15.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
|
||||
"integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
@ -749,9 +749,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
||||
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.6.tgz",
|
||||
"integrity": "sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -782,9 +782,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.24.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
||||
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
|
||||
"version": "4.24.5",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz",
|
||||
"integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -802,10 +802,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001688",
|
||||
"electron-to-chromium": "^1.5.73",
|
||||
"caniuse-lite": "^1.0.30001716",
|
||||
"electron-to-chromium": "^1.5.149",
|
||||
"node-releases": "^2.0.19",
|
||||
"update-browserslist-db": "^1.1.1"
|
||||
"update-browserslist-db": "^1.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@ -822,9 +822,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001707",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz",
|
||||
"integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==",
|
||||
"version": "1.0.30001718",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz",
|
||||
"integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -976,9 +976,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.128",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz",
|
||||
"integrity": "sha512-bo1A4HH/NS522Ws0QNFIzyPcyUUNV/yyy70Ho1xqfGYzPUme2F/xr4tlEOuM6/A538U1vDA7a4XfCd1CKRegKQ==",
|
||||
"version": "1.5.155",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz",
|
||||
"integrity": "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@ -1010,9 +1010,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
|
||||
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
||||
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -1107,13 +1107,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
|
||||
@ -1249,9 +1242,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz",
|
||||
"integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz",
|
||||
"integrity": "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -1755,16 +1748,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -1878,9 +1861,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.85.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz",
|
||||
"integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
|
||||
"version": "1.88.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.88.0.tgz",
|
||||
"integrity": "sha512-sF6TWQqjFvr4JILXzG4ucGOLELkESHL+I5QJhh7CNaE+Yge0SI+ehCatsXhJ7ymU1hAFcIS3/PBpjdIbXoyVbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1899,9 +1882,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass-loader": {
|
||||
"version": "16.0.4",
|
||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.4.tgz",
|
||||
"integrity": "sha512-LavLbgbBGUt3wCiYzhuLLu65+fWXaXLmq7YxivLhEqmiupCFZ5sKUAipK3do6V80YSU0jvSxNhEdT13IXNr3rg==",
|
||||
"version": "16.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz",
|
||||
"integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1940,9 +1923,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/schema-utils": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
|
||||
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
|
||||
"integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1960,9 +1943,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
@ -2079,9 +2062,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
|
||||
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -2089,14 +2072,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.39.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
|
||||
"integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
|
||||
"version": "5.39.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.2.tgz",
|
||||
"integrity": "sha512-yEPUmWve+VA78bI71BW70Dh0TuV4HHd+I5SHOAfS1+QBOmvmCiiffgjR8ryyEd3KIfvPGFqoADt8LdQ6XpXIvg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
"acorn": "^8.14.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
@ -2165,9 +2148,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -2202,16 +2185,6 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
@ -2220,9 +2193,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
|
||||
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -2234,14 +2207,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.97.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
|
||||
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
|
||||
"version": "5.99.8",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz",
|
||||
"integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.6",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@webassemblyjs/ast": "^1.14.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.14.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.14.1",
|
||||
@ -2258,9 +2232,9 @@
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.2.0",
|
||||
"schema-utils": "^4.3.2",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
@ -2361,59 +2335,6 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webpack/node_modules/schema-utils": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
|
||||
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"build": "webpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap": "5.3.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.7.1",
|
||||
"toastr": "2.1.4"
|
||||
@ -17,9 +17,9 @@
|
||||
"css-loader": "7.1.2",
|
||||
"expose-loader": "5.0.1",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"sass": "1.85.0",
|
||||
"sass-loader": "16.0.4",
|
||||
"webpack": "5.97.1",
|
||||
"sass": "1.88.0",
|
||||
"sass-loader": "16.0.5",
|
||||
"webpack": "5.99.8",
|
||||
"webpack-cli": "5.1.4"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!obj/build-output/publish/*
|
||||
!obj/Docker/empty/
|
||||
!entrypoint.sh
|
@ -2,13 +2,11 @@
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@ -137,7 +135,6 @@ public class OrganizationDomainController : Controller
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("domain/sso/verified")]
|
||||
[RequireFeature(FeatureFlagKeys.VerifiedSsoDomainEndpoint)]
|
||||
public async Task<VerifiedOrganizationDomainSsoDetailsResponseModel> GetVerifiedOrgDomainSsoDetailsAsync(
|
||||
[FromBody] OrganizationDomainSsoDetailsRequestModel model)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
|
@ -2,7 +2,7 @@
|
||||
using Bit.Api.Billing.Models.Requests;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Business;
|
||||
|
@ -2,10 +2,10 @@
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.Integrations;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Integrations;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.Integrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Integrations;
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.25.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -25,7 +25,7 @@ public class UpdateTwoFactorAuthenticatorRequestModel : SecretVerificationReques
|
||||
{
|
||||
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
|
||||
}
|
||||
else if (providers.ContainsKey(TwoFactorProviderType.Authenticator))
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.Authenticator);
|
||||
}
|
||||
@ -62,7 +62,7 @@ public class UpdateTwoFactorDuoRequestModel : SecretVerificationRequestModel, IV
|
||||
{
|
||||
providers = [];
|
||||
}
|
||||
else if (providers.ContainsKey(TwoFactorProviderType.Duo))
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.Duo);
|
||||
}
|
||||
@ -88,7 +88,7 @@ public class UpdateTwoFactorDuoRequestModel : SecretVerificationRequestModel, IV
|
||||
{
|
||||
providers = [];
|
||||
}
|
||||
else if (providers.ContainsKey(TwoFactorProviderType.OrganizationDuo))
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.OrganizationDuo);
|
||||
}
|
||||
@ -145,7 +145,7 @@ public class UpdateTwoFactorYubicoOtpRequestModel : SecretVerificationRequestMod
|
||||
{
|
||||
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
|
||||
}
|
||||
else if (providers.ContainsKey(TwoFactorProviderType.YubiKey))
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.YubiKey);
|
||||
}
|
||||
@ -228,7 +228,7 @@ public class TwoFactorEmailRequestModel : SecretVerificationRequestModel
|
||||
{
|
||||
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
|
||||
}
|
||||
else if (providers.ContainsKey(TwoFactorProviderType.Email))
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.Email);
|
||||
}
|
||||
|
@ -90,6 +90,13 @@ public class EmergencyAccessGrantorDetailsResponseModel : EmergencyAccessRespons
|
||||
|
||||
public class EmergencyAccessTakeoverResponseModel : ResponseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EmergencyAccessTakeoverResponseModel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="emergencyAccess">Consumed for the Encrypted Key value</param>
|
||||
/// <param name="grantor">consumed for the KDF configuration</param>
|
||||
/// <param name="obj">name of the object</param>
|
||||
/// <exception cref="ArgumentNullException">emergencyAccess cannot be null</exception>
|
||||
public EmergencyAccessTakeoverResponseModel(EmergencyAccess emergencyAccess, User grantor, string obj = "emergencyAccessTakeover") : base(obj)
|
||||
{
|
||||
if (emergencyAccess == null)
|
||||
|
@ -13,9 +13,9 @@ public class TwoFactorAuthenticatorResponseModel : ResponseModel
|
||||
ArgumentNullException.ThrowIfNull(user);
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Authenticator);
|
||||
if (provider?.MetaData?.ContainsKey("Key") ?? false)
|
||||
if (provider?.MetaData?.TryGetValue("Key", out var keyValue) ?? false)
|
||||
{
|
||||
Key = (string)provider.MetaData["Key"];
|
||||
Key = (string)keyValue;
|
||||
Enabled = provider.Enabled;
|
||||
}
|
||||
else
|
||||
|
@ -15,9 +15,9 @@ public class TwoFactorEmailResponseModel : ResponseModel
|
||||
}
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Email);
|
||||
if (provider?.MetaData?.ContainsKey("Email") ?? false)
|
||||
if (provider?.MetaData?.TryGetValue("Email", out var email) ?? false)
|
||||
{
|
||||
Email = (string)provider.MetaData["Email"];
|
||||
Email = (string)email;
|
||||
Enabled = provider.Enabled;
|
||||
}
|
||||
else
|
||||
|
@ -19,29 +19,29 @@ public class TwoFactorYubiKeyResponseModel : ResponseModel
|
||||
{
|
||||
Enabled = provider.Enabled;
|
||||
|
||||
if (provider.MetaData.ContainsKey("Key1"))
|
||||
if (provider.MetaData.TryGetValue("Key1", out var key1))
|
||||
{
|
||||
Key1 = (string)provider.MetaData["Key1"];
|
||||
Key1 = (string)key1;
|
||||
}
|
||||
if (provider.MetaData.ContainsKey("Key2"))
|
||||
if (provider.MetaData.TryGetValue("Key2", out var key2))
|
||||
{
|
||||
Key2 = (string)provider.MetaData["Key2"];
|
||||
Key2 = (string)key2;
|
||||
}
|
||||
if (provider.MetaData.ContainsKey("Key3"))
|
||||
if (provider.MetaData.TryGetValue("Key3", out var key3))
|
||||
{
|
||||
Key3 = (string)provider.MetaData["Key3"];
|
||||
Key3 = (string)key3;
|
||||
}
|
||||
if (provider.MetaData.ContainsKey("Key4"))
|
||||
if (provider.MetaData.TryGetValue("Key4", out var key4))
|
||||
{
|
||||
Key4 = (string)provider.MetaData["Key4"];
|
||||
Key4 = (string)key4;
|
||||
}
|
||||
if (provider.MetaData.ContainsKey("Key5"))
|
||||
if (provider.MetaData.TryGetValue("Key5", out var key5))
|
||||
{
|
||||
Key5 = (string)provider.MetaData["Key5"];
|
||||
Key5 = (string)key5;
|
||||
}
|
||||
if (provider.MetaData.ContainsKey("Nfc"))
|
||||
if (provider.MetaData.TryGetValue("Nfc", out var nfc))
|
||||
{
|
||||
Nfc = (bool)provider.MetaData["Nfc"];
|
||||
Nfc = (bool)nfc;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -6,14 +6,10 @@ using Bit.Api.Utilities;
|
||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -161,8 +157,6 @@ public class AccountsController(
|
||||
[HttpPost("cancel")]
|
||||
public async Task PostCancelAsync(
|
||||
[FromBody] SubscriptionCancellationRequestModel request,
|
||||
[FromServices] ICurrentContext currentContext,
|
||||
[FromServices] IReferenceEventService referenceEventService,
|
||||
[FromServices] ISubscriberService subscriberService)
|
||||
{
|
||||
var user = await userService.GetUserByPrincipalAsync(User);
|
||||
@ -175,12 +169,6 @@ public class AccountsController(
|
||||
await subscriberService.CancelSubscription(user,
|
||||
new OffboardingSurveyResponse { UserId = user.Id, Reason = request.Reason, Feedback = request.Feedback },
|
||||
user.IsExpired());
|
||||
|
||||
await referenceEventService.RaiseEventAsync(new ReferenceEvent(
|
||||
ReferenceEventType.CancelSubscription,
|
||||
user,
|
||||
currentContext)
|
||||
{ EndOfPeriod = user.IsExpired() });
|
||||
}
|
||||
|
||||
[HttpPost("reinstate-premium")]
|
||||
|
@ -4,10 +4,11 @@ using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.Billing.Models.Requests;
|
||||
using Bit.Api.Billing.Models.Responses;
|
||||
using Bit.Api.Billing.Queries.Organizations;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Models.Sales;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Tax.Models;
|
||||
using Bit.Core.Context;
|
||||
@ -24,7 +25,6 @@ namespace Bit.Api.Billing.Controllers;
|
||||
public class OrganizationBillingController(
|
||||
IBusinessUnitConverter businessUnitConverter,
|
||||
ICurrentContext currentContext,
|
||||
IFeatureService featureService,
|
||||
IOrganizationBillingService organizationBillingService,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IOrganizationWarningsQuery organizationWarningsQuery,
|
||||
@ -281,17 +281,36 @@ public class OrganizationBillingController(
|
||||
}
|
||||
|
||||
var organization = await organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
if (organization == null)
|
||||
{
|
||||
return Error.NotFound();
|
||||
}
|
||||
var existingPlan = organization.PlanType;
|
||||
var organizationSignup = model.ToOrganizationSignup(user);
|
||||
var sale = OrganizationSale.From(organization, organizationSignup);
|
||||
var plan = await pricingClient.GetPlanOrThrow(model.PlanType);
|
||||
sale.Organization.PlanType = plan.Type;
|
||||
sale.Organization.Plan = plan.Name;
|
||||
sale.SubscriptionSetup.SkipTrial = true;
|
||||
if (existingPlan == PlanType.Free && organization.GatewaySubscriptionId is not null)
|
||||
{
|
||||
sale.Organization.UseTotp = plan.HasTotp;
|
||||
sale.Organization.UseGroups = plan.HasGroups;
|
||||
sale.Organization.UseDirectory = plan.HasDirectory;
|
||||
sale.Organization.SelfHost = plan.HasSelfHost;
|
||||
sale.Organization.UsersGetPremium = plan.UsersGetPremium;
|
||||
sale.Organization.UseEvents = plan.HasEvents;
|
||||
sale.Organization.Use2fa = plan.Has2fa;
|
||||
sale.Organization.UseApi = plan.HasApi;
|
||||
sale.Organization.UsePolicies = plan.HasPolicies;
|
||||
sale.Organization.UseSso = plan.HasSso;
|
||||
sale.Organization.UseResetPassword = plan.HasResetPassword;
|
||||
sale.Organization.UseKeyConnector = plan.HasKeyConnector;
|
||||
sale.Organization.UseScim = plan.HasScim;
|
||||
sale.Organization.UseCustomPermissions = plan.HasCustomPermissions;
|
||||
sale.Organization.UseOrganizationDomains = plan.HasOrganizationDomains;
|
||||
sale.Organization.MaxCollections = plan.PasswordManager.MaxCollections;
|
||||
}
|
||||
|
||||
if (organizationSignup.PaymentMethodType == null || string.IsNullOrEmpty(organizationSignup.PaymentToken))
|
||||
{
|
||||
@ -301,8 +320,12 @@ public class OrganizationBillingController(
|
||||
Debug.Assert(org is not null, "This organization has already been found via this same ID, this should be fine.");
|
||||
var paymentSource = new TokenizedPaymentSource(organizationSignup.PaymentMethodType.Value, organizationSignup.PaymentToken);
|
||||
var taxInformation = TaxInformation.From(organizationSignup.TaxInfo);
|
||||
await organizationBillingService.UpdatePaymentMethod(org, paymentSource, taxInformation);
|
||||
await organizationBillingService.Finalize(sale);
|
||||
var updatedOrg = await organizationRepository.GetByIdAsync(organizationId);
|
||||
if (updatedOrg != null)
|
||||
{
|
||||
await organizationBillingService.UpdatePaymentMethod(updatedOrg, paymentSource, taxInformation);
|
||||
}
|
||||
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
@ -313,14 +336,6 @@ public class OrganizationBillingController(
|
||||
[FromRoute] Guid organizationId,
|
||||
[FromBody] SetupBusinessUnitRequestBody requestBody)
|
||||
{
|
||||
var enableOrganizationBusinessUnitConversion =
|
||||
featureService.IsEnabled(FeatureFlagKeys.PM18770_EnableOrganizationBusinessUnitConversion);
|
||||
|
||||
if (!enableOrganizationBusinessUnitConversion)
|
||||
{
|
||||
return Error.NotFound();
|
||||
}
|
||||
|
||||
var organization = await organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
if (organization == null)
|
||||
|
@ -20,9 +20,6 @@ using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -44,7 +41,6 @@ public class OrganizationsController(
|
||||
IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand,
|
||||
IUpgradeOrganizationPlanCommand upgradeOrganizationPlanCommand,
|
||||
IAddSecretsManagerSubscriptionCommand addSecretsManagerSubscriptionCommand,
|
||||
IReferenceEventService referenceEventService,
|
||||
ISubscriberService subscriberService,
|
||||
IOrganizationInstallationRepository organizationInstallationRepository,
|
||||
IPricingClient pricingClient)
|
||||
@ -246,14 +242,6 @@ public class OrganizationsController(
|
||||
Feedback = request.Feedback
|
||||
},
|
||||
organization.IsExpired());
|
||||
|
||||
await referenceEventService.RaiseEventAsync(new ReferenceEvent(
|
||||
ReferenceEventType.CancelSubscription,
|
||||
organization,
|
||||
currentContext)
|
||||
{
|
||||
EndOfPeriod = organization.IsExpired()
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/reinstate")]
|
||||
|
@ -1,10 +1,12 @@
|
||||
using Bit.Api.Billing.Models.Requests;
|
||||
using Bit.Api.Billing.Models.Responses;
|
||||
using Bit.Commercial.Core.Billing.Providers.Services;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Models;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Tax.Models;
|
||||
using Bit.Core.Context;
|
||||
@ -79,13 +81,6 @@ public class ProviderBillingController(
|
||||
[FromRoute] Guid providerId,
|
||||
[FromBody] UpdatePaymentMethodRequestBody requestBody)
|
||||
{
|
||||
var allowProviderPaymentMethod = featureService.IsEnabled(FeatureFlagKeys.PM18794_ProviderPaymentMethod);
|
||||
|
||||
if (!allowProviderPaymentMethod)
|
||||
{
|
||||
return TypedResults.NotFound();
|
||||
}
|
||||
|
||||
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
||||
|
||||
if (provider == null)
|
||||
@ -109,13 +104,6 @@ public class ProviderBillingController(
|
||||
[FromRoute] Guid providerId,
|
||||
[FromBody] VerifyBankAccountRequestBody requestBody)
|
||||
{
|
||||
var allowProviderPaymentMethod = featureService.IsEnabled(FeatureFlagKeys.PM18794_ProviderPaymentMethod);
|
||||
|
||||
if (!allowProviderPaymentMethod)
|
||||
{
|
||||
return TypedResults.NotFound();
|
||||
}
|
||||
|
||||
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
||||
|
||||
if (provider == null)
|
||||
@ -148,13 +136,33 @@ public class ProviderBillingController(
|
||||
|
||||
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
|
||||
|
||||
var getProviderPriceFromStripe = featureService.IsEnabled(FeatureFlagKeys.PM21383_GetProviderPriceFromStripe);
|
||||
|
||||
var configuredProviderPlans = await Task.WhenAll(providerPlans.Select(async providerPlan =>
|
||||
{
|
||||
var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType);
|
||||
|
||||
decimal unitAmount;
|
||||
|
||||
if (getProviderPriceFromStripe)
|
||||
{
|
||||
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, plan.Type);
|
||||
var price = await stripeAdapter.PriceGetAsync(priceId);
|
||||
|
||||
unitAmount = price.UnitAmountDecimal.HasValue
|
||||
? price.UnitAmountDecimal.Value / 100M
|
||||
: plan.PasswordManager.ProviderPortalSeatPrice;
|
||||
}
|
||||
else
|
||||
{
|
||||
unitAmount = plan.PasswordManager.ProviderPortalSeatPrice;
|
||||
}
|
||||
|
||||
return new ConfiguredProviderPlan(
|
||||
providerPlan.Id,
|
||||
providerPlan.ProviderId,
|
||||
plan,
|
||||
unitAmount,
|
||||
providerPlan.SeatMinimum ?? 0,
|
||||
providerPlan.PurchasedSeats ?? 0,
|
||||
providerPlan.AllocatedSeats ?? 0);
|
||||
|
@ -12,7 +12,8 @@ public record OrganizationMetadataResponse(
|
||||
bool IsSubscriptionCanceled,
|
||||
DateTime? InvoiceDueDate,
|
||||
DateTime? InvoiceCreatedDate,
|
||||
DateTime? SubPeriodEndDate)
|
||||
DateTime? SubPeriodEndDate,
|
||||
int OrganizationOccupiedSeats)
|
||||
{
|
||||
public static OrganizationMetadataResponse From(OrganizationMetadata metadata)
|
||||
=> new(
|
||||
@ -25,5 +26,6 @@ public record OrganizationMetadataResponse(
|
||||
metadata.IsSubscriptionCanceled,
|
||||
metadata.InvoiceDueDate,
|
||||
metadata.InvoiceCreatedDate,
|
||||
metadata.SubPeriodEndDate);
|
||||
metadata.SubPeriodEndDate,
|
||||
metadata.OrganizationOccupiedSeats);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models;
|
||||
using Bit.Core.Billing.Providers.Models;
|
||||
using Bit.Core.Billing.Tax.Models;
|
||||
using Stripe;
|
||||
|
||||
@ -35,7 +36,7 @@ public record ProviderSubscriptionResponse(
|
||||
.Select(providerPlan =>
|
||||
{
|
||||
var plan = providerPlan.Plan;
|
||||
var cost = (providerPlan.SeatMinimum + providerPlan.PurchasedSeats) * plan.PasswordManager.ProviderPortalSeatPrice;
|
||||
var cost = (providerPlan.SeatMinimum + providerPlan.PurchasedSeats) * providerPlan.Price;
|
||||
var cadence = plan.IsAnnual ? _annualCadence : _monthlyCadence;
|
||||
return new ProviderPlanResponse(
|
||||
plan.Name,
|
||||
|
@ -1,6 +1,50 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
# We put the value in a file to be read by later layers.
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY . ./
|
||||
|
||||
# Restore project dependencies and tools
|
||||
WORKDIR /source/src/Api
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Build project
|
||||
RUN . /tmp/rid.txt && dotnet publish \
|
||||
-c release \
|
||||
--no-restore \
|
||||
--self-contained \
|
||||
/p:PublishSingleFile=true \
|
||||
-r $RID \
|
||||
-o out
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
ENV SSL_CERT_DIR=/etc/bitwarden/ca-certificates
|
||||
EXPOSE 5000
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
@ -9,13 +53,11 @@ RUN apt-get update \
|
||||
krb5-user \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ASPNETCORE_URLS http://+:5000
|
||||
# Copy app from the build stage
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
COPY obj/build-output/publish .
|
||||
COPY entrypoint.sh /
|
||||
COPY --from=build /source/src/Api/out /app
|
||||
COPY ./src/Api/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
@ -5,7 +5,6 @@ using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Identity;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
@ -16,9 +15,6 @@ using Bit.Core.SecretsManager.Queries.Interfaces;
|
||||
using Bit.Core.SecretsManager.Queries.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@ -30,7 +26,6 @@ public class SecretsController : Controller
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly ISecretRepository _secretRepository;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly ICreateSecretCommand _createSecretCommand;
|
||||
private readonly IUpdateSecretCommand _updateSecretCommand;
|
||||
private readonly IDeleteSecretCommand _deleteSecretCommand;
|
||||
@ -39,14 +34,12 @@ public class SecretsController : Controller
|
||||
private readonly ISecretAccessPoliciesUpdatesQuery _secretAccessPoliciesUpdatesQuery;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
|
||||
public SecretsController(
|
||||
ICurrentContext currentContext,
|
||||
IProjectRepository projectRepository,
|
||||
ISecretRepository secretRepository,
|
||||
IOrganizationRepository organizationRepository,
|
||||
ICreateSecretCommand createSecretCommand,
|
||||
IUpdateSecretCommand updateSecretCommand,
|
||||
IDeleteSecretCommand deleteSecretCommand,
|
||||
@ -55,13 +48,11 @@ public class SecretsController : Controller
|
||||
ISecretAccessPoliciesUpdatesQuery secretAccessPoliciesUpdatesQuery,
|
||||
IUserService userService,
|
||||
IEventService eventService,
|
||||
IReferenceEventService referenceEventService,
|
||||
IAuthorizationService authorizationService)
|
||||
{
|
||||
_currentContext = currentContext;
|
||||
_projectRepository = projectRepository;
|
||||
_secretRepository = secretRepository;
|
||||
_organizationRepository = organizationRepository;
|
||||
_createSecretCommand = createSecretCommand;
|
||||
_updateSecretCommand = updateSecretCommand;
|
||||
_deleteSecretCommand = deleteSecretCommand;
|
||||
@ -70,7 +61,6 @@ public class SecretsController : Controller
|
||||
_secretAccessPoliciesUpdatesQuery = secretAccessPoliciesUpdatesQuery;
|
||||
_userService = userService;
|
||||
_eventService = eventService;
|
||||
_referenceEventService = referenceEventService;
|
||||
_authorizationService = authorizationService;
|
||||
|
||||
}
|
||||
@ -148,9 +138,6 @@ public class SecretsController : Controller
|
||||
if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount)
|
||||
{
|
||||
await _eventService.LogServiceAccountSecretEventAsync(userId, secret, EventType.Secret_Retrieved);
|
||||
|
||||
var org = await _organizationRepository.GetByIdAsync(secret.OrganizationId);
|
||||
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.SmServiceAccountAccessedSecret, org, _currentContext));
|
||||
}
|
||||
|
||||
return new SecretResponseModel(secret, access.Read, access.Write);
|
||||
@ -266,7 +253,7 @@ public class SecretsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
await LogSecretsRetrievalAsync(secrets.First().OrganizationId, secrets);
|
||||
await LogSecretsRetrievalAsync(secrets);
|
||||
|
||||
var responses = secrets.Select(s => new BaseSecretResponseModel(s));
|
||||
return new ListResponseModel<BaseSecretResponseModel>(responses);
|
||||
@ -303,21 +290,18 @@ public class SecretsController : Controller
|
||||
|
||||
if (syncResult.HasChanges)
|
||||
{
|
||||
await LogSecretsRetrievalAsync(organizationId, syncResult.Secrets);
|
||||
await LogSecretsRetrievalAsync(syncResult.Secrets);
|
||||
}
|
||||
|
||||
return new SecretsSyncResponseModel(syncResult.HasChanges, syncResult.Secrets);
|
||||
}
|
||||
|
||||
private async Task LogSecretsRetrievalAsync(Guid organizationId, IEnumerable<Secret> secrets)
|
||||
private async Task LogSecretsRetrievalAsync(IEnumerable<Secret> secrets)
|
||||
{
|
||||
if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User)!.Value;
|
||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
await _eventService.LogServiceAccountSecretsEventAsync(userId, secrets, EventType.Secret_Retrieved);
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.SmServiceAccountAccessedSecret, org, _currentContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,10 +28,8 @@ using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Api.Auth.Models.Request.WebAuthn;
|
||||
using Bit.Api.Billing;
|
||||
using Bit.Core.AdminConsole.Services.NoopImplementations;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Identity.TokenProviders;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tools.ImportFeatures;
|
||||
using Bit.Core.Auth.Models.Api.Request;
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures;
|
||||
@ -224,18 +222,8 @@ public class Startup
|
||||
services.AddHostedService<Core.HostedServices.ApplicationCacheHostedService>();
|
||||
}
|
||||
|
||||
// Slack
|
||||
if (CoreHelpers.SettingHasValue(globalSettings.Slack.ClientId) &&
|
||||
CoreHelpers.SettingHasValue(globalSettings.Slack.ClientSecret) &&
|
||||
CoreHelpers.SettingHasValue(globalSettings.Slack.Scopes))
|
||||
{
|
||||
services.AddHttpClient(SlackService.HttpClientName);
|
||||
services.AddSingleton<ISlackService, SlackService>();
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<ISlackService, NoopSlackService>();
|
||||
}
|
||||
// Add SlackService for OAuth API requests - if configured
|
||||
services.AddSlackService(globalSettings);
|
||||
}
|
||||
|
||||
public void Configure(
|
||||
|
@ -5,7 +5,6 @@ using Bit.Api.Tools.Models.Request;
|
||||
using Bit.Api.Tools.Models.Response;
|
||||
using Bit.Api.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
@ -33,7 +32,6 @@ public class SendsController : Controller
|
||||
private readonly INonAnonymousSendCommand _nonAnonymousSendCommand;
|
||||
private readonly ILogger<SendsController> _logger;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public SendsController(
|
||||
ISendRepository sendRepository,
|
||||
@ -43,8 +41,7 @@ public class SendsController : Controller
|
||||
INonAnonymousSendCommand nonAnonymousSendCommand,
|
||||
ISendFileStorageService sendFileStorageService,
|
||||
ILogger<SendsController> logger,
|
||||
GlobalSettings globalSettings,
|
||||
ICurrentContext currentContext)
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_sendRepository = sendRepository;
|
||||
_userService = userService;
|
||||
@ -54,7 +51,6 @@ public class SendsController : Controller
|
||||
_sendFileStorageService = sendFileStorageService;
|
||||
_logger = logger;
|
||||
_globalSettings = globalSettings;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
#region Anonymous endpoints
|
||||
|
@ -62,9 +62,9 @@ public static class ApiHelpers
|
||||
}
|
||||
}
|
||||
|
||||
if (eventTypeHandlers.ContainsKey(eventGridEvent.EventType))
|
||||
if (eventTypeHandlers.TryGetValue(eventGridEvent.EventType, out var eventTypeHandler))
|
||||
{
|
||||
await eventTypeHandlers[eventGridEvent.EventType](eventGridEvent);
|
||||
await eventTypeHandler(eventGridEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,6 @@ public class CiphersController : Controller
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly ILogger<CiphersController> _logger;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly IOrganizationCiphersQuery _organizationCiphersQuery;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly ICollectionRepository _collectionRepository;
|
||||
@ -57,7 +56,6 @@ public class CiphersController : Controller
|
||||
ICurrentContext currentContext,
|
||||
ILogger<CiphersController> logger,
|
||||
GlobalSettings globalSettings,
|
||||
IFeatureService featureService,
|
||||
IOrganizationCiphersQuery organizationCiphersQuery,
|
||||
IApplicationCacheService applicationCacheService,
|
||||
ICollectionRepository collectionRepository)
|
||||
@ -71,7 +69,6 @@ public class CiphersController : Controller
|
||||
_currentContext = currentContext;
|
||||
_logger = logger;
|
||||
_globalSettings = globalSettings;
|
||||
_featureService = featureService;
|
||||
_organizationCiphersQuery = organizationCiphersQuery;
|
||||
_applicationCacheService = applicationCacheService;
|
||||
_collectionRepository = collectionRepository;
|
||||
@ -151,6 +148,16 @@ public class CiphersController : Controller
|
||||
public async Task<CipherResponseModel> Post([FromBody] CipherRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.EncryptedFor != null)
|
||||
{
|
||||
if (model.EncryptedFor != user.Id)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
var cipher = model.ToCipherDetails(user.Id);
|
||||
if (cipher.OrganizationId.HasValue && !await _currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
{
|
||||
@ -170,6 +177,16 @@ public class CiphersController : Controller
|
||||
public async Task<CipherResponseModel> PostCreate([FromBody] CipherCreateRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.Cipher.EncryptedFor != null)
|
||||
{
|
||||
if (model.Cipher.EncryptedFor != user.Id)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
var cipher = model.Cipher.ToCipherDetails(user.Id);
|
||||
if (cipher.OrganizationId.HasValue && !await _currentContext.OrganizationUser(cipher.OrganizationId.Value))
|
||||
{
|
||||
@ -192,6 +209,16 @@ public class CiphersController : Controller
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.Cipher.EncryptedFor != null)
|
||||
{
|
||||
if (model.Cipher.EncryptedFor != userId)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
await _cipherService.SaveAsync(cipher, userId, model.Cipher.LastKnownRevisionDate, model.CollectionIds, true, false);
|
||||
|
||||
var response = new CipherMiniResponseModel(cipher, _globalSettings, false);
|
||||
@ -209,6 +236,15 @@ public class CiphersController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.EncryptedFor != null)
|
||||
{
|
||||
if (model.EncryptedFor != user.Id)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
ValidateClientVersionForFido2CredentialSupport(cipher);
|
||||
|
||||
var collectionIds = (await _collectionCipherRepository.GetManyByUserIdCipherIdAsync(user.Id, id)).Select(c => c.CollectionId).ToList();
|
||||
@ -237,6 +273,15 @@ public class CiphersController : Controller
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(id);
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.EncryptedFor != null)
|
||||
{
|
||||
if (model.EncryptedFor != userId)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
ValidateClientVersionForFido2CredentialSupport(cipher);
|
||||
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
@ -327,11 +372,6 @@ public class CiphersController : Controller
|
||||
|
||||
private async Task<bool> CanDeleteOrRestoreCipherAsAdminAsync(Guid organizationId, IEnumerable<Guid> cipherIds)
|
||||
{
|
||||
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitItemDeletion))
|
||||
{
|
||||
return await CanEditCipherAsAdminAsync(organizationId, cipherIds);
|
||||
}
|
||||
|
||||
var org = _currentContext.GetOrganization(organizationId);
|
||||
|
||||
// If we're not an "admin" or if we're a provider user we don't need to check the ciphers
|
||||
@ -658,6 +698,15 @@ public class CiphersController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// Validate the model was encrypted for the posting user
|
||||
if (model.Cipher.EncryptedFor != null)
|
||||
{
|
||||
if (model.Cipher.EncryptedFor != user.Id)
|
||||
{
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
ValidateClientVersionForFido2CredentialSupport(cipher);
|
||||
|
||||
var original = cipher.Clone();
|
||||
@ -1007,7 +1056,7 @@ public class CiphersController : Controller
|
||||
|
||||
[HttpPut("share")]
|
||||
[HttpPost("share")]
|
||||
public async Task PutShareMany([FromBody] CipherBulkShareRequestModel model)
|
||||
public async Task<ListResponseModel<CipherMiniResponseModel>> PutShareMany([FromBody] CipherBulkShareRequestModel model)
|
||||
{
|
||||
var organizationId = new Guid(model.Ciphers.First().OrganizationId);
|
||||
if (!await _currentContext.OrganizationUser(organizationId))
|
||||
@ -1016,26 +1065,41 @@ public class CiphersController : Controller
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId, withOrganizations: false);
|
||||
var ciphersDict = ciphers.ToDictionary(c => c.Id);
|
||||
|
||||
var shareCiphers = new List<(Cipher, DateTime?)>();
|
||||
// Validate the model was encrypted for the posting user
|
||||
foreach (var cipher in model.Ciphers)
|
||||
{
|
||||
if (!ciphersDict.ContainsKey(cipher.Id.Value))
|
||||
if (cipher.EncryptedFor.HasValue && cipher.EncryptedFor.Value != userId)
|
||||
{
|
||||
throw new BadRequestException("Trying to move ciphers that you do not own.");
|
||||
throw new BadRequestException("Cipher was not encrypted for the current user. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
var existingCipher = ciphersDict[cipher.Id.Value];
|
||||
var shareCiphers = new List<(CipherDetails, DateTime?)>();
|
||||
foreach (var cipher in model.Ciphers)
|
||||
{
|
||||
if (!ciphersDict.TryGetValue(cipher.Id.Value, out var existingCipher))
|
||||
{
|
||||
throw new BadRequestException("Trying to share ciphers that you do not own.");
|
||||
}
|
||||
|
||||
ValidateClientVersionForFido2CredentialSupport(existingCipher);
|
||||
|
||||
shareCiphers.Add((cipher.ToCipher(existingCipher), cipher.LastKnownRevisionDate));
|
||||
shareCiphers.Add((cipher.ToCipherDetails(existingCipher), cipher.LastKnownRevisionDate));
|
||||
}
|
||||
|
||||
await _cipherService.ShareManyAsync(shareCiphers, organizationId,
|
||||
model.CollectionIds.Select(c => new Guid(c)), userId);
|
||||
var updated = await _cipherService.ShareManyAsync(
|
||||
shareCiphers,
|
||||
organizationId,
|
||||
model.CollectionIds.Select(Guid.Parse),
|
||||
userId
|
||||
);
|
||||
|
||||
var response = updated.Select(c => new CipherMiniResponseModel(c, _globalSettings, c.OrganizationUseTotp));
|
||||
return new ListResponseModel<CipherMiniResponseModel>(response);
|
||||
}
|
||||
|
||||
[HttpPost("purge")]
|
||||
@ -1117,14 +1181,14 @@ public class CiphersController : Controller
|
||||
var cipher = await GetByIdAsync(id, userId);
|
||||
var attachments = cipher?.GetAttachments();
|
||||
|
||||
if (attachments == null || !attachments.ContainsKey(attachmentId) || attachments[attachmentId].Validated)
|
||||
if (attachments == null || !attachments.TryGetValue(attachmentId, out var attachment) || attachment.Validated)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new AttachmentUploadDataResponseModel
|
||||
{
|
||||
Url = await _attachmentStorageService.GetAttachmentUploadUrlAsync(cipher, attachments[attachmentId]),
|
||||
Url = await _attachmentStorageService.GetAttachmentUploadUrlAsync(cipher, attachment),
|
||||
FileUploadType = _attachmentStorageService.FileUploadType,
|
||||
};
|
||||
}
|
||||
@ -1143,11 +1207,10 @@ public class CiphersController : Controller
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await GetByIdAsync(id, userId);
|
||||
var attachments = cipher?.GetAttachments();
|
||||
if (attachments == null || !attachments.ContainsKey(attachmentId))
|
||||
if (attachments == null || !attachments.TryGetValue(attachmentId, out var attachmentData))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
var attachmentData = attachments[attachmentId];
|
||||
|
||||
await Request.GetFileAsync(async (stream) =>
|
||||
{
|
||||
@ -1297,7 +1360,7 @@ public class CiphersController : Controller
|
||||
var cipher = await _cipherRepository.GetByIdAsync(new Guid(cipherId));
|
||||
var attachments = cipher?.GetAttachments() ?? new Dictionary<string, CipherAttachment.MetaData>();
|
||||
|
||||
if (cipher == null || !attachments.ContainsKey(attachmentId) || attachments[attachmentId].Validated)
|
||||
if (cipher == null || !attachments.TryGetValue(attachmentId, out var attachment) || attachment.Validated)
|
||||
{
|
||||
if (_attachmentStorageService is AzureSendFileStorageService azureFileStorageService)
|
||||
{
|
||||
@ -1307,7 +1370,7 @@ public class CiphersController : Controller
|
||||
return;
|
||||
}
|
||||
|
||||
await _cipherService.ValidateCipherAttachmentFile(cipher, attachments[attachmentId]);
|
||||
await _cipherService.ValidateCipherAttachmentFile(cipher, attachment);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -1,9 +1,7 @@
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Api.Vault.Models.Response;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Commands.Interfaces;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Enums;
|
||||
@ -15,7 +13,6 @@ namespace Bit.Api.Vault.Controllers;
|
||||
|
||||
[Route("tasks")]
|
||||
[Authorize("Application")]
|
||||
[RequireFeature(FeatureFlagKeys.SecurityTasks)]
|
||||
public class SecurityTaskController : Controller
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
|
@ -11,6 +11,10 @@ namespace Bit.Api.Vault.Models.Request;
|
||||
|
||||
public class CipherRequestModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The Id of the user that encrypted the cipher. It should always represent a UserId.
|
||||
/// </summary>
|
||||
public Guid? EncryptedFor { get; set; }
|
||||
public CipherType Type { get; set; }
|
||||
|
||||
[StringLength(36)]
|
||||
@ -109,18 +113,25 @@ public class CipherRequestModel
|
||||
|
||||
if (hasAttachments2)
|
||||
{
|
||||
foreach (var attachment in attachments.Where(a => Attachments2.ContainsKey(a.Key)))
|
||||
foreach (var attachment in attachments)
|
||||
{
|
||||
var attachment2 = Attachments2[attachment.Key];
|
||||
if (!Attachments2.TryGetValue(attachment.Key, out var attachment2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
attachment.Value.FileName = attachment2.FileName;
|
||||
attachment.Value.Key = attachment2.Key;
|
||||
}
|
||||
}
|
||||
else if (hasAttachments)
|
||||
{
|
||||
foreach (var attachment in attachments.Where(a => Attachments.ContainsKey(a.Key)))
|
||||
foreach (var attachment in attachments)
|
||||
{
|
||||
attachment.Value.FileName = Attachments[attachment.Key];
|
||||
if (!Attachments.TryGetValue(attachment.Key, out var attachmentForKey))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
attachment.Value.FileName = attachmentForKey;
|
||||
attachment.Value.Key = null;
|
||||
}
|
||||
}
|
||||
|
@ -129,13 +129,13 @@ public class CipherDetailsResponseModel : CipherResponseModel
|
||||
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, string obj = "cipherDetails")
|
||||
: base(cipher, user, organizationAbilities, globalSettings, obj)
|
||||
{
|
||||
if (collectionCiphers?.ContainsKey(cipher.Id) ?? false)
|
||||
if (collectionCiphers?.TryGetValue(cipher.Id, out var collectionCipher) ?? false)
|
||||
{
|
||||
CollectionIds = collectionCiphers[cipher.Id].Select(c => c.CollectionId);
|
||||
CollectionIds = collectionCipher.Select(c => c.CollectionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
CollectionIds = new Guid[] { };
|
||||
CollectionIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ public class CipherDetailsResponseModel : CipherResponseModel
|
||||
IEnumerable<CollectionCipher> collectionCiphers, string obj = "cipherDetails")
|
||||
: base(cipher, user, organizationAbilities, globalSettings, obj)
|
||||
{
|
||||
CollectionIds = collectionCiphers?.Select(c => c.CollectionId) ?? new List<Guid>();
|
||||
CollectionIds = collectionCiphers?.Select(c => c.CollectionId) ?? [];
|
||||
}
|
||||
|
||||
public CipherDetailsResponseModel(
|
||||
@ -158,7 +158,7 @@ public class CipherDetailsResponseModel : CipherResponseModel
|
||||
string obj = "cipherDetails")
|
||||
: base(cipher, user, organizationAbilities, globalSettings, obj)
|
||||
{
|
||||
CollectionIds = cipher.CollectionIds ?? new List<Guid>();
|
||||
CollectionIds = cipher.CollectionIds ?? [];
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> CollectionIds { get; set; }
|
||||
@ -170,13 +170,13 @@ public class CipherMiniDetailsResponseModel : CipherMiniResponseModel
|
||||
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, bool orgUseTotp, string obj = "cipherMiniDetails")
|
||||
: base(cipher, globalSettings, orgUseTotp, obj)
|
||||
{
|
||||
if (collectionCiphers?.ContainsKey(cipher.Id) ?? false)
|
||||
if (collectionCiphers?.TryGetValue(cipher.Id, out var collectionCipher) ?? false)
|
||||
{
|
||||
CollectionIds = collectionCiphers[cipher.Id].Select(c => c.CollectionId);
|
||||
CollectionIds = collectionCipher.Select(c => c.CollectionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
CollectionIds = new Guid[] { };
|
||||
CollectionIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ public class CipherMiniDetailsResponseModel : CipherMiniResponseModel
|
||||
GlobalSettings globalSettings, bool orgUseTotp, string obj = "cipherMiniDetails")
|
||||
: base(cipher, globalSettings, orgUseTotp, obj)
|
||||
{
|
||||
CollectionIds = cipher.CollectionIds ?? new List<Guid>();
|
||||
CollectionIds = cipher.CollectionIds ?? [];
|
||||
}
|
||||
|
||||
public CipherMiniDetailsResponseModel(CipherOrganizationDetailsWithCollections cipher,
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Setup
|
||||
|
||||
@ -19,31 +19,36 @@ then
|
||||
LGID=65534
|
||||
fi
|
||||
|
||||
# Create user and group
|
||||
if [ "$(id -u)" = "0" ]
|
||||
then
|
||||
# Create user and group
|
||||
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
|
||||
# The rest...
|
||||
# The rest...
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
fi
|
||||
|
||||
gosu_cmd="gosu $USERNAME:$GROUPNAME"
|
||||
else
|
||||
gosu_cmd=""
|
||||
fi
|
||||
|
||||
if [[ -f "/etc/bitwarden/kerberos/bitwarden.keytab" && -f "/etc/bitwarden/kerberos/krb5.conf" ]]; then
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden/kerberos
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
gosu $USERNAME:$GROUPNAME kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
cp -f /etc/bitwarden/kerberos/krb5.conf /etc/krb5.conf
|
||||
$gosu_cmd kinit $globalSettings__kerberosUser -k -t /etc/bitwarden/kerberos/bitwarden.keytab
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Api.dll
|
||||
exec $gosu_cmd /app/Api
|
||||
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!obj/build-output/publish/*
|
||||
!obj/Docker/empty/
|
||||
!entrypoint.sh
|
@ -10,7 +10,7 @@
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -28,8 +28,8 @@ public class AppleController : Controller
|
||||
return new BadRequestResult();
|
||||
}
|
||||
|
||||
var key = HttpContext.Request.Query.ContainsKey("key") ?
|
||||
HttpContext.Request.Query["key"].ToString() : null;
|
||||
var key = HttpContext.Request.Query.TryGetValue("key", out var keyValue) ?
|
||||
keyValue.ToString() : null;
|
||||
if (!CoreHelpers.FixedTimeEquals(key, _billingSettings.AppleWebhookKey))
|
||||
{
|
||||
return new BadRequestResult();
|
||||
|
@ -51,8 +51,8 @@ public class PayPalController : Controller
|
||||
[HttpPost("ipn")]
|
||||
public async Task<IActionResult> PostIpn()
|
||||
{
|
||||
var key = HttpContext.Request.Query.ContainsKey("key")
|
||||
? HttpContext.Request.Query["key"].ToString()
|
||||
var key = HttpContext.Request.Query.TryGetValue("key", out var keyValue)
|
||||
? keyValue.ToString()
|
||||
: null;
|
||||
|
||||
if (string.IsNullOrEmpty(key))
|
||||
|
@ -1,6 +1,50 @@
|
||||
###############################################
|
||||
# Build stage #
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
# Docker buildx supplies the value for this arg
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Determine proper runtime value for .NET
|
||||
# We put the value in a file to be read by later layers.
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
RID=linux-x64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
RID=linux-arm64 ; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
RID=linux-arm ; \
|
||||
fi \
|
||||
&& echo "RID=$RID" > /tmp/rid.txt
|
||||
|
||||
# Copy required project files
|
||||
WORKDIR /source
|
||||
COPY . ./
|
||||
|
||||
# Restore project dependencies and tools
|
||||
WORKDIR /source/src/Billing
|
||||
RUN . /tmp/rid.txt && dotnet restore -r $RID
|
||||
|
||||
# Build project
|
||||
RUN . /tmp/rid.txt && dotnet publish \
|
||||
-c release \
|
||||
--no-restore \
|
||||
--self-contained \
|
||||
/p:PublishSingleFile=true \
|
||||
-r $RID \
|
||||
-o out
|
||||
|
||||
###############################################
|
||||
# App stage #
|
||||
###############################################
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
LABEL com.bitwarden.product="bitwarden"
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
ENV SSL_CERT_DIR=/etc/bitwarden/ca-certificates
|
||||
EXPOSE 5000
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
@ -8,14 +52,11 @@ RUN apt-get update \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ASPNETCORE_URLS http://+:5000
|
||||
# Copy app from the build stage
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
COPY entrypoint.sh /
|
||||
COPY --from=build /source/src/Billing/out /app
|
||||
COPY ./src/Billing/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
COPY obj/build-output/publish .
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
@ -20,8 +20,8 @@ public class Program
|
||||
return e.Level >= globalSettings.MinLogLevel.BillingSettings.Jobs;
|
||||
}
|
||||
|
||||
if (e.Properties.ContainsKey("RequestPath") &&
|
||||
!string.IsNullOrWhiteSpace(e.Properties["RequestPath"]?.ToString()) &&
|
||||
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
|
||||
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
|
||||
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
|
||||
{
|
||||
return false;
|
||||
|
@ -1,8 +1,4 @@
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Repositories;
|
||||
using Event = Stripe.Event;
|
||||
|
||||
namespace Bit.Billing.Services.Implementations;
|
||||
@ -10,23 +6,17 @@ namespace Bit.Billing.Services.Implementations;
|
||||
public class CustomerUpdatedHandler : ICustomerUpdatedHandler
|
||||
{
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IStripeEventService _stripeEventService;
|
||||
private readonly IStripeEventUtilityService _stripeEventUtilityService;
|
||||
private readonly ILogger<CustomerUpdatedHandler> _logger;
|
||||
|
||||
public CustomerUpdatedHandler(
|
||||
IOrganizationRepository organizationRepository,
|
||||
IReferenceEventService referenceEventService,
|
||||
ICurrentContext currentContext,
|
||||
IStripeEventService stripeEventService,
|
||||
IStripeEventUtilityService stripeEventUtilityService,
|
||||
ILogger<CustomerUpdatedHandler> logger)
|
||||
{
|
||||
_organizationRepository = organizationRepository ?? throw new ArgumentNullException(nameof(organizationRepository));
|
||||
_referenceEventService = referenceEventService;
|
||||
_currentContext = currentContext;
|
||||
_stripeEventService = stripeEventService;
|
||||
_stripeEventUtilityService = stripeEventUtilityService;
|
||||
_logger = logger;
|
||||
@ -95,20 +85,5 @@ public class CustomerUpdatedHandler : ICustomerUpdatedHandler
|
||||
|
||||
organization.BillingEmail = customer.Email;
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
|
||||
if (_referenceEventService == null)
|
||||
{
|
||||
_logger.LogError("ReferenceEventService was not initialized in CustomerUpdatedHandler");
|
||||
throw new InvalidOperationException($"{nameof(_referenceEventService)} is not initialized");
|
||||
}
|
||||
|
||||
if (_currentContext == null)
|
||||
{
|
||||
_logger.LogError("CurrentContext was not initialized in CustomerUpdatedHandler");
|
||||
throw new InvalidOperationException($"{nameof(_currentContext)} is not initialized");
|
||||
}
|
||||
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.OrganizationEditedInStripe, organization, _currentContext));
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,9 @@ using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Event = Stripe.Event;
|
||||
|
||||
namespace Bit.Billing.Services.Implementations;
|
||||
@ -22,9 +18,6 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
private readonly IStripeFacade _stripeFacade;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IStripeEventUtilityService _stripeEventUtilityService;
|
||||
private readonly IPushNotificationService _pushNotificationService;
|
||||
private readonly IOrganizationEnableCommand _organizationEnableCommand;
|
||||
@ -36,9 +29,6 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
IStripeFacade stripeFacade,
|
||||
IProviderRepository providerRepository,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IReferenceEventService referenceEventService,
|
||||
ICurrentContext currentContext,
|
||||
IUserRepository userRepository,
|
||||
IStripeEventUtilityService stripeEventUtilityService,
|
||||
IUserService userService,
|
||||
IPushNotificationService pushNotificationService,
|
||||
@ -50,9 +40,6 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
_stripeFacade = stripeFacade;
|
||||
_providerRepository = providerRepository;
|
||||
_organizationRepository = organizationRepository;
|
||||
_referenceEventService = referenceEventService;
|
||||
_currentContext = currentContext;
|
||||
_userRepository = userRepository;
|
||||
_stripeEventUtilityService = stripeEventUtilityService;
|
||||
_userService = userService;
|
||||
_pushNotificationService = pushNotificationService;
|
||||
@ -116,27 +103,7 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
_logger.LogError("invoice.payment_succeeded webhook ({EventID}) for Provider ({ProviderID}) indicates missing subscription line items",
|
||||
parsedEvent.Id,
|
||||
provider.Id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await _referenceEventService.RaiseEventAsync(new ReferenceEvent
|
||||
{
|
||||
Type = ReferenceEventType.Rebilled,
|
||||
Source = ReferenceEventSource.Provider,
|
||||
Id = provider.Id,
|
||||
PlanType = PlanType.TeamsMonthly,
|
||||
Seats = (int)teamsMonthlyLineItem.Quantity
|
||||
});
|
||||
|
||||
await _referenceEventService.RaiseEventAsync(new ReferenceEvent
|
||||
{
|
||||
Type = ReferenceEventType.Rebilled,
|
||||
Source = ReferenceEventSource.Provider,
|
||||
Id = provider.Id,
|
||||
PlanType = PlanType.EnterpriseMonthly,
|
||||
Seats = (int)enterpriseMonthlyLineItem.Quantity
|
||||
});
|
||||
}
|
||||
else if (organizationId.HasValue)
|
||||
{
|
||||
@ -156,15 +123,6 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
|
||||
await _organizationEnableCommand.EnableAsync(organizationId.Value, subscription.CurrentPeriodEnd);
|
||||
await _pushNotificationService.PushSyncOrganizationStatusAsync(organization);
|
||||
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.Rebilled, organization, _currentContext)
|
||||
{
|
||||
PlanName = organization?.Plan,
|
||||
PlanType = organization?.PlanType,
|
||||
Seats = organization?.Seats,
|
||||
Storage = organization?.MaxStorageGb,
|
||||
});
|
||||
}
|
||||
else if (userId.HasValue)
|
||||
{
|
||||
@ -174,14 +132,6 @@ public class PaymentSucceededHandler : IPaymentSucceededHandler
|
||||
}
|
||||
|
||||
await _userService.EnablePremiumAsync(userId.Value, subscription.CurrentPeriodEnd);
|
||||
|
||||
var user = await _userRepository.GetByIdAsync(userId.Value);
|
||||
await _referenceEventService.RaiseEventAsync(
|
||||
new ReferenceEvent(ReferenceEventType.Rebilled, user, _currentContext)
|
||||
{
|
||||
PlanName = IStripeEventUtilityService.PremiumPlanId,
|
||||
Storage = user?.MaxStorageGb,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
using Bit.Billing.Constants;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Entities;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Repositories;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Stripe;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Setup
|
||||
|
||||
@ -19,25 +19,27 @@ then
|
||||
LGID=65534
|
||||
fi
|
||||
|
||||
# Create user and group
|
||||
if [ "$(id -u)" = "0" ]
|
||||
then
|
||||
# Create user and group
|
||||
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 ||
|
||||
groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1
|
||||
useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 ||
|
||||
usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1
|
||||
mkhomedir_helper $USERNAME
|
||||
|
||||
# The rest...
|
||||
# The rest...
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
mkdir -p /etc/bitwarden/core
|
||||
mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
gosu_cmd="gosu $USERNAME:$GROUPNAME"
|
||||
else
|
||||
gosu_cmd=""
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Billing.dll
|
||||
exec $gosu_cmd /app/Billing
|
||||
|
@ -8,14 +8,13 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.AdminConsole.Entities;
|
||||
|
||||
public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable, IReferenceable
|
||||
public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable
|
||||
{
|
||||
private Dictionary<TwoFactorProviderType, TwoFactorProvider>? _twoFactorProviders;
|
||||
|
||||
@ -258,12 +257,12 @@ public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable,
|
||||
public bool TwoFactorProviderIsEnabled(TwoFactorProviderType provider)
|
||||
{
|
||||
var providers = GetTwoFactorProviders();
|
||||
if (providers == null || !providers.ContainsKey(provider))
|
||||
if (providers == null || !providers.TryGetValue(provider, out var twoFactorProvider))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return providers[provider].Enabled && Use2fa;
|
||||
return twoFactorProvider.Enabled && Use2fa;
|
||||
}
|
||||
|
||||
public bool TwoFactorIsEnabled()
|
||||
@ -280,12 +279,7 @@ public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable,
|
||||
public TwoFactorProvider? GetTwoFactorProvider(TwoFactorProviderType provider)
|
||||
{
|
||||
var providers = GetTwoFactorProviders();
|
||||
if (providers == null || !providers.ContainsKey(provider))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return providers[provider];
|
||||
return providers?.GetValueOrDefault(provider);
|
||||
}
|
||||
|
||||
public void UpdateFromLicense(OrganizationLicense license, IFeatureService featureService)
|
||||
|
@ -7,3 +7,19 @@ public enum IntegrationType : int
|
||||
Slack = 3,
|
||||
Webhook = 4,
|
||||
}
|
||||
|
||||
public static class IntegrationTypeExtensions
|
||||
{
|
||||
public static string ToRoutingKey(this IntegrationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case IntegrationType.Slack:
|
||||
return "slack";
|
||||
case IntegrationType.Webhook:
|
||||
return "webhook";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported integration type: {type}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ public enum PolicyType : byte
|
||||
AutomaticAppLogIn = 12,
|
||||
FreeFamiliesSponsorshipPolicy = 13,
|
||||
RemoveUnlockWithPin = 14,
|
||||
RestrictedItemTypesPolicy = 15,
|
||||
}
|
||||
|
||||
public static class PolicyTypeExtensions
|
||||
@ -43,7 +44,8 @@ public static class PolicyTypeExtensions
|
||||
PolicyType.ActivateAutofill => "Active auto-fill",
|
||||
PolicyType.AutomaticAppLogIn => "Automatically log in users for allowed applications",
|
||||
PolicyType.FreeFamiliesSponsorshipPolicy => "Remove Free Bitwarden Families sponsorship",
|
||||
PolicyType.RemoveUnlockWithPin => "Remove unlock with PIN"
|
||||
PolicyType.RemoveUnlockWithPin => "Remove unlock with PIN",
|
||||
PolicyType.RestrictedItemTypesPolicy => "Restricted item types",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.Integrations;
|
||||
|
||||
public interface IIntegrationMessage
|
||||
{
|
||||
IntegrationType IntegrationType { get; }
|
||||
string MessageId { get; set; }
|
||||
int RetryCount { get; }
|
||||
DateTime? DelayUntilDate { get; }
|
||||
void ApplyRetry(DateTime? handlerDelayUntilDate);
|
||||
string ToJson();
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.Integrations;
|
||||
|
||||
public class IntegrationHandlerResult
|
||||
{
|
||||
public IntegrationHandlerResult(bool success, IIntegrationMessage message)
|
||||
{
|
||||
Success = success;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public bool Success { get; set; } = false;
|
||||
public bool Retryable { get; set; } = false;
|
||||
public IIntegrationMessage Message { get; set; }
|
||||
public DateTime? DelayUntilDate { get; set; }
|
||||
public string FailureReason { get; set; } = string.Empty;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user