mirror of
https://github.com/bitwarden/server.git
synced 2025-07-03 00:52:49 -05:00
Merge branch 'feature/flexible-collections' into flexible-collections/deprecate-custom-collection-perm
# Conflicts: # src/Api/AdminConsole/Controllers/GroupsController.cs # src/Api/AdminConsole/Controllers/OrganizationUsersController.cs # src/Core/Services/Implementations/OrganizationService.cs
This commit is contained in:
10
.github/CODEOWNERS
vendored
10
.github/CODEOWNERS
vendored
@ -9,6 +9,11 @@
|
|||||||
# DevOps for Actions and other workflow changes.
|
# DevOps for Actions and other workflow changes.
|
||||||
.github/workflows @bitwarden/dept-devops
|
.github/workflows @bitwarden/dept-devops
|
||||||
|
|
||||||
|
# DevOps for Docker changes.
|
||||||
|
**/Dockerfile @bitwarden/dept-devops
|
||||||
|
**/*.Dockerfile @bitwarden/dept-devops
|
||||||
|
**/.dockerignore @bitwarden/dept-devops
|
||||||
|
|
||||||
## Auth team files ##
|
## Auth team files ##
|
||||||
**/Auth @bitwarden/team-auth-dev
|
**/Auth @bitwarden/team-auth-dev
|
||||||
bitwarden_license/src/Sso @bitwarden/team-auth-dev
|
bitwarden_license/src/Sso @bitwarden/team-auth-dev
|
||||||
@ -16,13 +21,16 @@ src/Identity @bitwarden/team-auth-dev
|
|||||||
|
|
||||||
**/SecretsManager @bitwarden/team-secrets-manager-dev
|
**/SecretsManager @bitwarden/team-secrets-manager-dev
|
||||||
**/Tools @bitwarden/team-tools-dev
|
**/Tools @bitwarden/team-tools-dev
|
||||||
|
|
||||||
|
## Vault Team files
|
||||||
**/Vault @bitwarden/team-vault-dev
|
**/Vault @bitwarden/team-vault-dev
|
||||||
|
**/Vault/AuthorizationHandlers @bitwarden/team-vault-dev @bitwarden/team-admin-console-dev # joint ownership over authorization handlers that affect organization users
|
||||||
|
|
||||||
# Admin-Console Team
|
# Admin-Console Team
|
||||||
|
**/AdminConsole @bitwarden/team-admin-console-dev
|
||||||
bitwarden_license/src/Scim @bitwarden/team-admin-console-dev
|
bitwarden_license/src/Scim @bitwarden/team-admin-console-dev
|
||||||
bitwarden_license/src/test/Scim.IntegrationTest @bitwarden/team-admin-console-dev
|
bitwarden_license/src/test/Scim.IntegrationTest @bitwarden/team-admin-console-dev
|
||||||
bitwarden_license/src/test/Scim.ScimTest @bitwarden/team-admin-console-dev
|
bitwarden_license/src/test/Scim.ScimTest @bitwarden/team-admin-console-dev
|
||||||
**/AdminConsole @bitwarden/team-admin-console-dev
|
|
||||||
|
|
||||||
# Billing Team
|
# Billing Team
|
||||||
**/*billing* @bitwarden/team-billing-dev
|
**/*billing* @bitwarden/team-billing-dev
|
||||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -277,7 +277,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve github PAT secrets
|
- name: Retrieve github PAT secrets
|
||||||
id: retrieve-secret-pat
|
id: retrieve-secret-pat
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/get-keyvault-secrets@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
@ -528,7 +528,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve github PAT secrets
|
- name: Retrieve github PAT secrets
|
||||||
id: retrieve-secret-pat
|
id: retrieve-secret-pat
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/get-keyvault-secrets@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
@ -603,7 +603,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/get-keyvault-secrets@c970b0fb89bd966749280e832928db62040812bf
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
|
@ -92,7 +92,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/get-keyvault-secrets@c970b0fb89bd966749280e832928db62040812bf
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Check Release Version
|
- name: Check Release Version
|
||||||
id: version
|
id: version
|
||||||
uses: bitwarden/gh-actions/release-version-check@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/release-version-check@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
release-type: ${{ github.event.inputs.release_type }}
|
release-type: ${{ github.event.inputs.release_type }}
|
||||||
project-type: dotnet
|
project-type: dotnet
|
||||||
@ -89,7 +89,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Download latest Release ${{ matrix.name }} asset
|
- name: Download latest Release ${{ matrix.name }} asset
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/download-artifacts@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@ -98,7 +98,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Dry Run - Download latest Release ${{ matrix.name }} asset
|
- name: Dry Run - Download latest Release ${{ matrix.name }} asset
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/download-artifacts@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@ -274,7 +274,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Download latest Release Docker Stubs
|
- name: Download latest Release Docker Stubs
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/download-artifacts@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@ -287,7 +287,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Dry Run - Download latest Release Docker Stubs
|
- name: Dry Run - Download latest Release Docker Stubs
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/download-artifacts@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
4
.github/workflows/version-bump.yml
vendored
4
.github/workflows/version-bump.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/get-keyvault-secrets@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
|
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||||
@ -40,7 +40,7 @@ jobs:
|
|||||||
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
|
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
|
||||||
|
|
||||||
- name: Bump Version - Props
|
- name: Bump Version - Props
|
||||||
uses: bitwarden/gh-actions/version-bump@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/version-bump@c970b0fb89bd966749280e832928db62040812bf
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "Directory.Build.props"
|
file_path: "Directory.Build.props"
|
||||||
|
2
.github/workflows/workflow-linter.yml
vendored
2
.github/workflows/workflow-linter.yml
vendored
@ -8,4 +8,4 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
call-workflow:
|
call-workflow:
|
||||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@f1125802b1ccae8c601d7c4f61ce39ea254b10c8
|
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@c970b0fb89bd966749280e832928db62040812bf
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -225,4 +225,4 @@ src/Identity/Identity.zip
|
|||||||
src/Notifications/Notifications.zip
|
src/Notifications/Notifications.zip
|
||||||
bitwarden_license/src/Portal/Portal.zip
|
bitwarden_license/src/Portal/Portal.zip
|
||||||
bitwarden_license/src/Sso/Sso.zip
|
bitwarden_license/src/Sso/Sso.zip
|
||||||
src/Api/flags.json
|
**/src/*/flags.json
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Context;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.SecretsManager.AuthorizationRequirements;
|
using Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||||
|
@ -56,6 +56,9 @@ public class
|
|||||||
case not null when requirement == ServiceAccountOperations.RevokeAccessTokens:
|
case not null when requirement == ServiceAccountOperations.RevokeAccessTokens:
|
||||||
await CanRevokeAccessTokensAsync(context, requirement, resource);
|
await CanRevokeAccessTokensAsync(context, requirement, resource);
|
||||||
break;
|
break;
|
||||||
|
case not null when requirement == ServiceAccountOperations.ReadEvents:
|
||||||
|
await CanReadEventsAsync(context, requirement, resource);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException("Unsupported operation requirement type provided.",
|
throw new ArgumentException("Unsupported operation requirement type provided.",
|
||||||
nameof(requirement));
|
nameof(requirement));
|
||||||
@ -169,4 +172,19 @@ public class
|
|||||||
context.Succeed(requirement);
|
context.Succeed(requirement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CanReadEventsAsync(AuthorizationHandlerContext context,
|
||||||
|
ServiceAccountOperationRequirement requirement, ServiceAccount resource)
|
||||||
|
{
|
||||||
|
var (accessClient, userId) =
|
||||||
|
await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
|
||||||
|
var access =
|
||||||
|
await _serviceAccountRepository.AccessToServiceAccountAsync(resource.Id, userId,
|
||||||
|
accessClient);
|
||||||
|
|
||||||
|
if (access.Read)
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Scim.Groups.Interfaces;
|
using Bit.Scim.Groups.Interfaces;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Scim.Groups.Interfaces;
|
using Bit.Scim.Groups.Interfaces;
|
||||||
|
|
||||||
namespace Bit.Scim.Groups;
|
namespace Bit.Scim.Groups;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
namespace Bit.Scim.Groups.Interfaces;
|
namespace Bit.Scim.Groups.Interfaces;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
|
||||||
namespace Bit.Scim.Groups.Interfaces;
|
namespace Bit.Scim.Groups.Interfaces;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
|
||||||
namespace Bit.Scim.Groups.Interfaces;
|
namespace Bit.Scim.Groups.Interfaces;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
|
using Bit.Core.AdminConsole.Services;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Scim.Groups.Interfaces;
|
using Bit.Scim.Groups.Interfaces;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Scim.Context;
|
using Bit.Scim.Context;
|
||||||
using Bit.Scim.Groups.Interfaces;
|
using Bit.Scim.Groups.Interfaces;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Scim.Context;
|
using Bit.Scim.Context;
|
||||||
using Bit.Scim.Groups.Interfaces;
|
using Bit.Scim.Groups.Interfaces;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Scim.Models;
|
namespace Bit.Scim.Models;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
namespace Bit.Scim.Models;
|
namespace Bit.Scim.Models;
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Bit.Commercial.Core.SecretsManager.AuthorizationHandlers.AccessPolicies;
|
using Bit.Commercial.Core.SecretsManager.AuthorizationHandlers.AccessPolicies;
|
||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
@ -497,4 +497,63 @@ public class ServiceAccountAuthorizationHandlerTests
|
|||||||
|
|
||||||
Assert.Equal(expected, authzContext.HasSucceeded);
|
Assert.Equal(expected, authzContext.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task CanReadEvents_AccessToSecretsManagerFalse_DoesNotSucceed(
|
||||||
|
SutProvider<ServiceAccountAuthorizationHandler> sutProvider, ServiceAccount serviceAccount,
|
||||||
|
ClaimsPrincipal claimsPrincipal)
|
||||||
|
{
|
||||||
|
var requirement = ServiceAccountOperations.ReadEvents;
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(serviceAccount.OrganizationId)
|
||||||
|
.Returns(false);
|
||||||
|
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||||
|
claimsPrincipal, serviceAccount);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(authzContext);
|
||||||
|
|
||||||
|
Assert.False(authzContext.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task CanReadEvents_NullResource_DoesNotSucceed(
|
||||||
|
SutProvider<ServiceAccountAuthorizationHandler> sutProvider, ServiceAccount serviceAccount,
|
||||||
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Guid userId)
|
||||||
|
{
|
||||||
|
var requirement = ServiceAccountOperations.ReadEvents;
|
||||||
|
SetupPermission(sutProvider, PermissionType.RunAsAdmin, serviceAccount.OrganizationId, userId);
|
||||||
|
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||||
|
claimsPrincipal, null);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(authzContext);
|
||||||
|
|
||||||
|
Assert.False(authzContext.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(PermissionType.RunAsAdmin, true, true, true)]
|
||||||
|
[BitAutoData(PermissionType.RunAsUserWithPermission, false, false, false)]
|
||||||
|
[BitAutoData(PermissionType.RunAsUserWithPermission, false, true, false)]
|
||||||
|
[BitAutoData(PermissionType.RunAsUserWithPermission, true, false, true)]
|
||||||
|
[BitAutoData(PermissionType.RunAsUserWithPermission, true, true, true)]
|
||||||
|
public async Task CanReadEvents_AccessCheck(PermissionType permissionType, bool read, bool write,
|
||||||
|
bool expected,
|
||||||
|
SutProvider<ServiceAccountAuthorizationHandler> sutProvider, ServiceAccount serviceAccount,
|
||||||
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Guid userId)
|
||||||
|
{
|
||||||
|
var requirement = ServiceAccountOperations.ReadEvents;
|
||||||
|
SetupPermission(sutProvider, permissionType, serviceAccount.OrganizationId, userId);
|
||||||
|
sutProvider.GetDependency<IServiceAccountRepository>()
|
||||||
|
.AccessToServiceAccountAsync(serviceAccount.Id, userId, Arg.Any<AccessClientType>())
|
||||||
|
.Returns((read, write));
|
||||||
|
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||||
|
claimsPrincipal, serviceAccount);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(authzContext);
|
||||||
|
|
||||||
|
Assert.Equal(expected, authzContext.HasSucceeded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Scim.Groups;
|
using Bit.Scim.Groups;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
|
using Bit.Core.AdminConsole.Services;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Scim.Groups;
|
using Bit.Scim.Groups;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
using Bit.Scim.Utilities;
|
using Bit.Scim.Utilities;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Scim.Context;
|
using Bit.Scim.Context;
|
||||||
using Bit.Scim.Groups;
|
using Bit.Scim.Groups;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Scim.Context;
|
using Bit.Scim.Context;
|
||||||
using Bit.Scim.Groups;
|
using Bit.Scim.Groups;
|
||||||
using Bit.Scim.Models;
|
using Bit.Scim.Models;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
using Bit.Admin.Models;
|
using Bit.Admin.Models;
|
||||||
using Bit.Admin.Services;
|
using Bit.Admin.Services;
|
||||||
using Bit.Admin.Utilities;
|
using Bit.Admin.Utilities;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Entities.Provider;
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Entities.Provider;
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
using Bit.Api.Models.Request;
|
using Bit.Api.AdminConsole.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Vault.AuthorizationHandlers.Groups;
|
using Bit.Api.Vault.AuthorizationHandlers.Groups;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
|
using Bit.Core.AdminConsole.Services;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("organizations/{orgId}/groups")]
|
[Route("organizations/{orgId}/groups")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,8 +1,10 @@
|
|||||||
using Bit.Api.Models.Request.Organizations;
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
using Bit.Api.Models.Request.Organizations;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Models.Response.Organizations;
|
|
||||||
using Bit.Api.Vault.AuthorizationHandlers.OrganizationUsers;
|
using Bit.Api.Vault.AuthorizationHandlers.OrganizationUsers;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
@ -16,7 +18,7 @@ using Bit.Core.Services;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("organizations/{orgId}/users")]
|
[Route("organizations/{orgId}/users")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,4 +1,8 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Api.AdminConsole.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
using Bit.Api.Auth.Models.Request.Accounts;
|
using Bit.Api.Auth.Models.Request.Accounts;
|
||||||
using Bit.Api.Auth.Models.Request.Organizations;
|
using Bit.Api.Auth.Models.Request.Organizations;
|
||||||
using Bit.Api.Auth.Models.Response.Organizations;
|
using Bit.Api.Auth.Models.Response.Organizations;
|
||||||
@ -6,7 +10,6 @@ using Bit.Api.Models.Request;
|
|||||||
using Bit.Api.Models.Request.Accounts;
|
using Bit.Api.Models.Request.Accounts;
|
||||||
using Bit.Api.Models.Request.Organizations;
|
using Bit.Api.Models.Request.Organizations;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Models.Response.Organizations;
|
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Auth.Enums;
|
using Bit.Core.Auth.Enums;
|
||||||
using Bit.Core.Auth.Repositories;
|
using Bit.Core.Auth.Repositories;
|
||||||
@ -26,7 +29,7 @@ using Bit.Core.Utilities;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("organizations")]
|
[Route("organizations")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,4 +1,4 @@
|
|||||||
using Bit.Api.Models.Request;
|
using Bit.Api.AdminConsole.Models.Request;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("organizations/{orgId}/policies")]
|
[Route("organizations/{orgId}/policies")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Api.Models.Request.Providers;
|
using Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Models.Response.Providers;
|
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
@ -9,7 +9,7 @@ using Bit.Core.Utilities;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("providers/{providerId:guid}/organizations")]
|
[Route("providers/{providerId:guid}/organizations")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Api.Models.Request.Providers;
|
using Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Models.Response.Providers;
|
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Business.Provider;
|
using Bit.Core.Models.Business.Provider;
|
||||||
@ -9,7 +9,7 @@ using Bit.Core.Services;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("providers/{providerId:guid}/users")]
|
[Route("providers/{providerId:guid}/users")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,5 +1,5 @@
|
|||||||
using Bit.Api.Models.Request.Providers;
|
using Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
using Bit.Api.Models.Response.Providers;
|
using Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
@ -8,7 +8,7 @@ using Bit.Core.Settings;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Controllers;
|
namespace Bit.Api.AdminConsole.Controllers;
|
||||||
|
|
||||||
[Route("providers")]
|
[Route("providers")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
@ -1,7 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Core.Entities;
|
using Bit.Api.Models.Request;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request;
|
namespace Bit.Api.AdminConsole.Models.Request;
|
||||||
|
|
||||||
public class GroupRequestModel
|
public class GroupRequestModel
|
||||||
{
|
{
|
@ -1,7 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request;
|
||||||
|
|
||||||
public class ImportOrganizationUsersRequestModel
|
public class ImportOrganizationUsersRequestModel
|
||||||
{
|
{
|
||||||
@ -24,7 +25,7 @@ public class ImportOrganizationUsersRequestModel
|
|||||||
{
|
{
|
||||||
var importedGroup = new ImportedGroup
|
var importedGroup = new ImportedGroup
|
||||||
{
|
{
|
||||||
Group = new Core.Entities.Group
|
Group = new Core.AdminConsole.Entities.Group
|
||||||
{
|
{
|
||||||
OrganizationId = organizationId,
|
OrganizationId = organizationId,
|
||||||
Name = Name,
|
Name = Name,
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Api.Auth.Models.Request.Accounts;
|
using Bit.Api.Auth.Models.Request.Accounts;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Accounts;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationApiKeyRequestModel : SecretVerificationRequestModel
|
public class OrganizationApiKeyRequestModel : SecretVerificationRequestModel
|
||||||
{
|
{
|
@ -4,7 +4,7 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationCreateRequestModel : IValidatableObject
|
public class OrganizationCreateRequestModel : IValidatableObject
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationKeysRequestModel
|
public class OrganizationKeysRequestModel
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationSeatRequestModel : IValidatableObject
|
public class OrganizationSeatRequestModel : IValidatableObject
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using Bit.Core.Entities;
|
|||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationUpdateRequestModel
|
public class OrganizationUpdateRequestModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationUpgradeRequestModel
|
public class OrganizationUpgradeRequestModel
|
||||||
{
|
{
|
@ -1,11 +1,12 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Api.Models.Request;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationUserInviteRequestModel
|
public class OrganizationUserInviteRequestModel
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using System.Text.Json;
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request;
|
namespace Bit.Api.AdminConsole.Models.Request;
|
||||||
|
|
||||||
public class PolicyRequestModel
|
public class PolicyRequestModel
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Providers;
|
namespace Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
|
||||||
public class ProviderOrganizationAddRequestModel
|
public class ProviderOrganizationAddRequestModel
|
||||||
{
|
{
|
@ -1,8 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Api.Models.Request.Organizations;
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Providers;
|
namespace Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
|
||||||
public class ProviderOrganizationCreateRequestModel
|
public class ProviderOrganizationCreateRequestModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Core.Entities.Provider;
|
using Bit.Core.Entities.Provider;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Providers;
|
namespace Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
|
||||||
public class ProviderSetupRequestModel
|
public class ProviderSetupRequestModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Entities.Provider;
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Providers;
|
namespace Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
|
||||||
public class ProviderUpdateRequestModel
|
public class ProviderUpdateRequestModel
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using Bit.Core.Entities.Provider;
|
|||||||
using Bit.Core.Enums.Provider;
|
using Bit.Core.Enums.Provider;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Providers;
|
namespace Bit.Api.AdminConsole.Models.Request.Providers;
|
||||||
|
|
||||||
public class ProviderUserInviteRequestModel
|
public class ProviderUserInviteRequestModel
|
||||||
{
|
{
|
@ -1,8 +1,9 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Api.Models.Response;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response;
|
namespace Bit.Api.AdminConsole.Models.Response;
|
||||||
|
|
||||||
public class GroupResponseModel : ResponseModel
|
public class GroupResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationApiKeyInformation : ResponseModel
|
public class OrganizationApiKeyInformation : ResponseModel
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationAutoEnrollStatusResponseModel : ResponseModel
|
public class OrganizationAutoEnrollStatusResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationKeysResponseModel : ResponseModel
|
public class OrganizationKeysResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationPublicKeyResponseModel : ResponseModel
|
public class OrganizationPublicKeyResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -1,11 +1,12 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Api.Models.Response;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Constants = Bit.Core.Constants;
|
using Constants = Bit.Core.Constants;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationResponseModel : ResponseModel
|
public class OrganizationResponseModel : ResponseModel
|
||||||
{
|
{
|
||||||
@ -113,7 +114,7 @@ public class OrganizationSubscriptionResponseModel : OrganizationResponseModel
|
|||||||
{
|
{
|
||||||
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
||||||
UpcomingInvoice = subscription.UpcomingInvoice != null ? new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
UpcomingInvoice = subscription.UpcomingInvoice != null ? new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
||||||
Discount = subscription.Discount != null ? new BillingCustomerDiscount(subscription.Discount) : null;
|
CustomerDiscount = subscription.CustomerDiscount != null ? new BillingCustomerDiscount(subscription.CustomerDiscount) : null;
|
||||||
Expiration = DateTime.UtcNow.AddYears(1); // Not used, so just give it a value.
|
Expiration = DateTime.UtcNow.AddYears(1); // Not used, so just give it a value.
|
||||||
|
|
||||||
if (hideSensitiveData)
|
if (hideSensitiveData)
|
||||||
@ -144,7 +145,7 @@ public class OrganizationSubscriptionResponseModel : OrganizationResponseModel
|
|||||||
|
|
||||||
public string StorageName { get; set; }
|
public string StorageName { get; set; }
|
||||||
public double? StorageGb { get; set; }
|
public double? StorageGb { get; set; }
|
||||||
public BillingCustomerDiscount Discount { get; set; }
|
public BillingCustomerDiscount CustomerDiscount { get; set; }
|
||||||
public BillingSubscription Subscription { get; set; }
|
public BillingSubscription Subscription { get; set; }
|
||||||
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
@ -6,7 +7,7 @@ using Bit.Core.Models.Data;
|
|||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
|
||||||
public class OrganizationUserResponseModel : ResponseModel
|
public class OrganizationUserResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -7,7 +7,7 @@ using Bit.Core.Models.Data;
|
|||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response;
|
namespace Bit.Api.AdminConsole.Models.Response;
|
||||||
|
|
||||||
public class ProfileOrganizationResponseModel : ResponseModel
|
public class ProfileOrganizationResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response;
|
namespace Bit.Api.AdminConsole.Models.Response;
|
||||||
|
|
||||||
public class ProfileProviderOrganizationResponseModel : ProfileOrganizationResponseModel
|
public class ProfileProviderOrganizationResponseModel : ProfileOrganizationResponseModel
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using Bit.Core.Models.Api;
|
|||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Providers;
|
namespace Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
|
|
||||||
public class ProfileProviderResponseModel : ResponseModel
|
public class ProfileProviderResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Providers;
|
namespace Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
|
|
||||||
public class ProviderOrganizationResponseModel : ResponseModel
|
public class ProviderOrganizationResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Core.Entities.Provider;
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Providers;
|
namespace Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
|
|
||||||
public class ProviderResponseModel : ResponseModel
|
public class ProviderResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -4,7 +4,7 @@ using Bit.Core.Models.Api;
|
|||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Providers;
|
namespace Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
|
|
||||||
public class ProviderUserResponseModel : ResponseModel
|
public class ProviderUserResponseModel : ResponseModel
|
||||||
{
|
{
|
@ -1,13 +1,15 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Bit.Api.Models.Public.Request;
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
using Bit.Api.Models.Public.Response;
|
using Bit.Api.Models.Public.Response;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.OrganizationFeatures.Groups.Interfaces;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Public.Controllers;
|
namespace Bit.Api.AdminConsole.Public.Controllers;
|
||||||
|
|
||||||
[Route("public/groups")]
|
[Route("public/groups")]
|
||||||
[Authorize("Organization")]
|
[Authorize("Organization")]
|
@ -1,6 +1,8 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Bit.Api.Models.Public.Request;
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
using Bit.Api.Models.Public.Response;
|
using Bit.Api.Models.Public.Response;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
@ -9,7 +11,7 @@ using Bit.Core.Services;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Public.Controllers;
|
namespace Bit.Api.AdminConsole.Public.Controllers;
|
||||||
|
|
||||||
[Route("public/members")]
|
[Route("public/members")]
|
||||||
[Authorize("Organization")]
|
[Authorize("Organization")]
|
@ -1,5 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Bit.Api.Models.Public.Request;
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
using Bit.Api.Models.Public.Response;
|
using Bit.Api.Models.Public.Response;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
@ -8,7 +9,7 @@ using Bit.Core.Settings;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Public.Controllers;
|
namespace Bit.Api.AdminConsole.Public.Controllers;
|
||||||
|
|
||||||
[Route("public/organization")]
|
[Route("public/organization")]
|
||||||
[Authorize("Organization")]
|
[Authorize("Organization")]
|
@ -1,5 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Bit.Api.Models.Public.Request;
|
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
using Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
using Bit.Api.Models.Public.Response;
|
using Bit.Api.Models.Public.Response;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@ -8,7 +9,7 @@ using Bit.Core.Services;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Bit.Api.Public.Controllers;
|
namespace Bit.Api.AdminConsole.Public.Controllers;
|
||||||
|
|
||||||
[Route("public/policies")]
|
[Route("public/policies")]
|
||||||
[Authorize("Organization")]
|
[Authorize("Organization")]
|
@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public;
|
namespace Bit.Api.AdminConsole.Public.Models;
|
||||||
|
|
||||||
public abstract class GroupBaseModel
|
public abstract class GroupBaseModel
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using Bit.Core.Entities;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public;
|
namespace Bit.Api.AdminConsole.Public.Models;
|
||||||
|
|
||||||
public abstract class MemberBaseModel
|
public abstract class MemberBaseModel
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public;
|
namespace Bit.Api.AdminConsole.Public.Models;
|
||||||
|
|
||||||
public abstract class PolicyBaseModel
|
public abstract class PolicyBaseModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Api.Auth.Models.Public.Request;
|
using Bit.Api.Auth.Models.Public.Request;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class GroupCreateUpdateRequestModel : GroupBaseModel
|
public class GroupCreateUpdateRequestModel : GroupBaseModel
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class MemberCreateRequestModel : MemberUpdateRequestModel
|
public class MemberCreateRequestModel : MemberUpdateRequestModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using Bit.Api.Auth.Models.Public.Request;
|
using Bit.Api.Auth.Models.Public.Request;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class MemberUpdateRequestModel : MemberBaseModel
|
public class MemberUpdateRequestModel : MemberBaseModel
|
||||||
{
|
{
|
@ -1,10 +1,11 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class OrganizationImportRequestModel
|
public class OrganizationImportRequestModel
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class PolicyUpdateRequestModel : PolicyBaseModel
|
public class PolicyUpdateRequestModel : PolicyBaseModel
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class UpdateGroupIdsRequestModel
|
public class UpdateGroupIdsRequestModel
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Api.Models.Public.Request;
|
namespace Bit.Api.AdminConsole.Public.Models.Request;
|
||||||
|
|
||||||
public class UpdateMemberIdsRequestModel
|
public class UpdateMemberIdsRequestModel
|
||||||
{
|
{
|
@ -1,9 +1,10 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Api.Auth.Models.Public.Response;
|
using Bit.Api.Auth.Models.Public.Response;
|
||||||
using Bit.Core.Entities;
|
using Bit.Api.Models.Public.Response;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Response;
|
namespace Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user group.
|
/// A user group.
|
@ -1,11 +1,12 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Api.Auth.Models.Public.Response;
|
using Bit.Api.Auth.Models.Public.Response;
|
||||||
|
using Bit.Api.Models.Public.Response;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Response;
|
namespace Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An organization member.
|
/// An organization member.
|
@ -1,9 +1,10 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Bit.Api.Models.Public.Response;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Public.Response;
|
namespace Bit.Api.AdminConsole.Public.Models.Response;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A policy.
|
/// A policy.
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Api.Auth.Models.Request;
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
|
using Bit.Api.Auth.Models.Request;
|
||||||
using Bit.Api.Auth.Models.Response;
|
using Bit.Api.Auth.Models.Response;
|
||||||
using Bit.Api.Models.Request.Organizations;
|
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.Vault.Models.Response;
|
using Bit.Api.Vault.Models.Response;
|
||||||
using Bit.Core.Auth.Services;
|
using Bit.Core.Auth.Services;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Api.Auth.Models.Request.Accounts;
|
using Bit.Api.AdminConsole.Models.Response;
|
||||||
|
using Bit.Api.Auth.Models.Request.Accounts;
|
||||||
using Bit.Api.Models.Request;
|
using Bit.Api.Models.Request;
|
||||||
using Bit.Api.Models.Request.Accounts;
|
using Bit.Api.Models.Request.Accounts;
|
||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
|
using Bit.Api.Utilities;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
@ -41,7 +42,7 @@ public class EventsController : Controller
|
|||||||
public async Task<ListResponseModel<EventResponseModel>> GetUser(
|
public async Task<ListResponseModel<EventResponseModel>> GetUser(
|
||||||
[FromQuery] DateTime? start = null, [FromQuery] DateTime? end = null, [FromQuery] string continuationToken = null)
|
[FromQuery] DateTime? start = null, [FromQuery] DateTime? end = null, [FromQuery] string continuationToken = null)
|
||||||
{
|
{
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var userId = _userService.GetProperUserId(User).Value;
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
var result = await _eventRepository.GetManyByUserAsync(userId, dateRange.Item1, dateRange.Item2,
|
var result = await _eventRepository.GetManyByUserAsync(userId, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
@ -75,7 +76,7 @@ public class EventsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var result = await _eventRepository.GetManyByCipherAsync(cipher, dateRange.Item1, dateRange.Item2,
|
var result = await _eventRepository.GetManyByCipherAsync(cipher, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
var responses = result.Data.Select(e => new EventResponseModel(e));
|
var responses = result.Data.Select(e => new EventResponseModel(e));
|
||||||
@ -92,7 +93,7 @@ public class EventsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var result = await _eventRepository.GetManyByOrganizationAsync(orgId, dateRange.Item1, dateRange.Item2,
|
var result = await _eventRepository.GetManyByOrganizationAsync(orgId, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
var responses = result.Data.Select(e => new EventResponseModel(e));
|
var responses = result.Data.Select(e => new EventResponseModel(e));
|
||||||
@ -110,7 +111,7 @@ public class EventsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var result = await _eventRepository.GetManyByOrganizationActingUserAsync(organizationUser.OrganizationId,
|
var result = await _eventRepository.GetManyByOrganizationActingUserAsync(organizationUser.OrganizationId,
|
||||||
organizationUser.UserId.Value, dateRange.Item1, dateRange.Item2,
|
organizationUser.UserId.Value, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
@ -127,7 +128,7 @@ public class EventsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var result = await _eventRepository.GetManyByProviderAsync(providerId, dateRange.Item1, dateRange.Item2,
|
var result = await _eventRepository.GetManyByProviderAsync(providerId, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
var responses = result.Data.Select(e => new EventResponseModel(e));
|
var responses = result.Data.Select(e => new EventResponseModel(e));
|
||||||
@ -145,33 +146,11 @@ public class EventsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dateRange = GetDateRange(start, end);
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
var result = await _eventRepository.GetManyByProviderActingUserAsync(providerUser.ProviderId,
|
var result = await _eventRepository.GetManyByProviderActingUserAsync(providerUser.ProviderId,
|
||||||
providerUser.UserId.Value, dateRange.Item1, dateRange.Item2,
|
providerUser.UserId.Value, dateRange.Item1, dateRange.Item2,
|
||||||
new PageOptions { ContinuationToken = continuationToken });
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
var responses = result.Data.Select(e => new EventResponseModel(e));
|
var responses = result.Data.Select(e => new EventResponseModel(e));
|
||||||
return new ListResponseModel<EventResponseModel>(responses, result.ContinuationToken);
|
return new ListResponseModel<EventResponseModel>(responses, result.ContinuationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tuple<DateTime, DateTime> GetDateRange(DateTime? start, DateTime? end)
|
|
||||||
{
|
|
||||||
if (!end.HasValue || !start.HasValue)
|
|
||||||
{
|
|
||||||
end = DateTime.UtcNow.Date.AddDays(1).AddMilliseconds(-1);
|
|
||||||
start = DateTime.UtcNow.Date.AddDays(-30);
|
|
||||||
}
|
|
||||||
else if (start.Value > end.Value)
|
|
||||||
{
|
|
||||||
var newEnd = start;
|
|
||||||
start = end;
|
|
||||||
end = newEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((end.Value - start.Value) > TimeSpan.FromDays(367))
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Range too large.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Tuple<DateTime, DateTime>(start.Value, end.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,12 @@ public class OrganizationConnectionsController : Controller
|
|||||||
[HttpPut("{organizationConnectionId}")]
|
[HttpPut("{organizationConnectionId}")]
|
||||||
public async Task<OrganizationConnectionResponseModel> UpdateConnection(Guid organizationConnectionId, [FromBody] OrganizationConnectionRequestModel model)
|
public async Task<OrganizationConnectionResponseModel> UpdateConnection(Guid organizationConnectionId, [FromBody] OrganizationConnectionRequestModel model)
|
||||||
{
|
{
|
||||||
var existingOrganizationConnection = await _organizationConnectionRepository.GetByIdAsync(organizationConnectionId);
|
if (model == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingOrganizationConnection = await _organizationConnectionRepository.GetByIdOrganizationIdAsync(organizationConnectionId, model.OrganizationId);
|
||||||
if (existingOrganizationConnection == null)
|
if (existingOrganizationConnection == null)
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
@ -19,7 +19,7 @@ public class OrganizationDomainController : Controller
|
|||||||
private readonly ICreateOrganizationDomainCommand _createOrganizationDomainCommand;
|
private readonly ICreateOrganizationDomainCommand _createOrganizationDomainCommand;
|
||||||
private readonly IVerifyOrganizationDomainCommand _verifyOrganizationDomainCommand;
|
private readonly IVerifyOrganizationDomainCommand _verifyOrganizationDomainCommand;
|
||||||
private readonly IDeleteOrganizationDomainCommand _deleteOrganizationDomainCommand;
|
private readonly IDeleteOrganizationDomainCommand _deleteOrganizationDomainCommand;
|
||||||
private readonly IGetOrganizationDomainByIdQuery _getOrganizationDomainByIdQuery;
|
private readonly IGetOrganizationDomainByIdOrganizationIdQuery _getOrganizationDomainByIdAndOrganizationIdQuery;
|
||||||
private readonly IGetOrganizationDomainByOrganizationIdQuery _getOrganizationDomainByOrganizationIdQuery;
|
private readonly IGetOrganizationDomainByOrganizationIdQuery _getOrganizationDomainByOrganizationIdQuery;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
@ -29,7 +29,7 @@ public class OrganizationDomainController : Controller
|
|||||||
ICreateOrganizationDomainCommand createOrganizationDomainCommand,
|
ICreateOrganizationDomainCommand createOrganizationDomainCommand,
|
||||||
IVerifyOrganizationDomainCommand verifyOrganizationDomainCommand,
|
IVerifyOrganizationDomainCommand verifyOrganizationDomainCommand,
|
||||||
IDeleteOrganizationDomainCommand deleteOrganizationDomainCommand,
|
IDeleteOrganizationDomainCommand deleteOrganizationDomainCommand,
|
||||||
IGetOrganizationDomainByIdQuery getOrganizationDomainByIdQuery,
|
IGetOrganizationDomainByIdOrganizationIdQuery getOrganizationDomainByIdAndOrganizationIdQuery,
|
||||||
IGetOrganizationDomainByOrganizationIdQuery getOrganizationDomainByOrganizationIdQuery,
|
IGetOrganizationDomainByOrganizationIdQuery getOrganizationDomainByOrganizationIdQuery,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -38,7 +38,7 @@ public class OrganizationDomainController : Controller
|
|||||||
_createOrganizationDomainCommand = createOrganizationDomainCommand;
|
_createOrganizationDomainCommand = createOrganizationDomainCommand;
|
||||||
_verifyOrganizationDomainCommand = verifyOrganizationDomainCommand;
|
_verifyOrganizationDomainCommand = verifyOrganizationDomainCommand;
|
||||||
_deleteOrganizationDomainCommand = deleteOrganizationDomainCommand;
|
_deleteOrganizationDomainCommand = deleteOrganizationDomainCommand;
|
||||||
_getOrganizationDomainByIdQuery = getOrganizationDomainByIdQuery;
|
_getOrganizationDomainByIdAndOrganizationIdQuery = getOrganizationDomainByIdAndOrganizationIdQuery;
|
||||||
_getOrganizationDomainByOrganizationIdQuery = getOrganizationDomainByOrganizationIdQuery;
|
_getOrganizationDomainByOrganizationIdQuery = getOrganizationDomainByOrganizationIdQuery;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -46,71 +46,78 @@ public class OrganizationDomainController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{orgId}/domain")]
|
[HttpGet("{orgId}/domain")]
|
||||||
public async Task<ListResponseModel<OrganizationDomainResponseModel>> Get(string orgId)
|
public async Task<ListResponseModel<OrganizationDomainResponseModel>> Get(Guid orgId)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(orgId);
|
await ValidateOrganizationAccessAsync(orgId);
|
||||||
await ValidateOrganizationAccessAsync(orgIdGuid);
|
|
||||||
|
|
||||||
var domains = await _getOrganizationDomainByOrganizationIdQuery
|
var domains = await _getOrganizationDomainByOrganizationIdQuery
|
||||||
.GetDomainsByOrganizationId(orgIdGuid);
|
.GetDomainsByOrganizationIdAsync(orgId);
|
||||||
var response = domains.Select(x => new OrganizationDomainResponseModel(x)).ToList();
|
var response = domains.Select(x => new OrganizationDomainResponseModel(x)).ToList();
|
||||||
return new ListResponseModel<OrganizationDomainResponseModel>(response);
|
return new ListResponseModel<OrganizationDomainResponseModel>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{orgId}/domain/{id}")]
|
[HttpGet("{orgId}/domain/{id}")]
|
||||||
public async Task<OrganizationDomainResponseModel> Get(string orgId, string id)
|
public async Task<OrganizationDomainResponseModel> Get(Guid orgId, Guid id)
|
||||||
{
|
{
|
||||||
var orgIdGuid = new Guid(orgId);
|
await ValidateOrganizationAccessAsync(orgId);
|
||||||
var IdGuid = new Guid(id);
|
|
||||||
await ValidateOrganizationAccessAsync(orgIdGuid);
|
|
||||||
|
|
||||||
var domain = await _getOrganizationDomainByIdQuery.GetOrganizationDomainById(IdGuid);
|
var organizationDomain = await _getOrganizationDomainByIdAndOrganizationIdQuery
|
||||||
|
.GetOrganizationDomainByIdOrganizationIdAsync(id, orgId);
|
||||||
|
if (organizationDomain is null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OrganizationDomainResponseModel(organizationDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{orgId}/domain")]
|
||||||
|
public async Task<OrganizationDomainResponseModel> Post(Guid orgId,
|
||||||
|
[FromBody] OrganizationDomainRequestModel model)
|
||||||
|
{
|
||||||
|
await ValidateOrganizationAccessAsync(orgId);
|
||||||
|
|
||||||
|
var organizationDomain = new OrganizationDomain
|
||||||
|
{
|
||||||
|
OrganizationId = orgId,
|
||||||
|
Txt = model.Txt,
|
||||||
|
DomainName = model.DomainName.ToLower()
|
||||||
|
};
|
||||||
|
|
||||||
|
organizationDomain = await _createOrganizationDomainCommand.CreateAsync(organizationDomain);
|
||||||
|
|
||||||
|
return new OrganizationDomainResponseModel(organizationDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{orgId}/domain/{id}/verify")]
|
||||||
|
public async Task<OrganizationDomainResponseModel> Verify(Guid orgId, Guid id)
|
||||||
|
{
|
||||||
|
await ValidateOrganizationAccessAsync(orgId);
|
||||||
|
|
||||||
|
var organizationDomain = await _organizationDomainRepository.GetDomainByIdOrganizationIdAsync(id, orgId);
|
||||||
|
if (organizationDomain is null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
organizationDomain = await _verifyOrganizationDomainCommand.VerifyOrganizationDomainAsync(organizationDomain);
|
||||||
|
|
||||||
|
return new OrganizationDomainResponseModel(organizationDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{orgId}/domain/{id}")]
|
||||||
|
[HttpPost("{orgId}/domain/{id}/remove")]
|
||||||
|
public async Task RemoveDomain(Guid orgId, Guid id)
|
||||||
|
{
|
||||||
|
await ValidateOrganizationAccessAsync(orgId);
|
||||||
|
|
||||||
|
var domain = await _organizationDomainRepository.GetDomainByIdOrganizationIdAsync(id, orgId);
|
||||||
if (domain is null)
|
if (domain is null)
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OrganizationDomainResponseModel(domain);
|
await _deleteOrganizationDomainCommand.DeleteAsync(domain);
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{orgId}/domain")]
|
|
||||||
public async Task<OrganizationDomainResponseModel> Post(string orgId,
|
|
||||||
[FromBody] OrganizationDomainRequestModel model)
|
|
||||||
{
|
|
||||||
var orgIdGuid = new Guid(orgId);
|
|
||||||
await ValidateOrganizationAccessAsync(orgIdGuid);
|
|
||||||
|
|
||||||
var organizationDomain = new OrganizationDomain
|
|
||||||
{
|
|
||||||
OrganizationId = orgIdGuid,
|
|
||||||
Txt = model.Txt,
|
|
||||||
DomainName = model.DomainName.ToLower()
|
|
||||||
};
|
|
||||||
|
|
||||||
var domain = await _createOrganizationDomainCommand.CreateAsync(organizationDomain);
|
|
||||||
return new OrganizationDomainResponseModel(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{orgId}/domain/{id}/verify")]
|
|
||||||
public async Task<OrganizationDomainResponseModel> Verify(string orgId, string id)
|
|
||||||
{
|
|
||||||
var orgIdGuid = new Guid(orgId);
|
|
||||||
var idGuid = new Guid(id);
|
|
||||||
await ValidateOrganizationAccessAsync(orgIdGuid);
|
|
||||||
|
|
||||||
var domain = await _verifyOrganizationDomainCommand.VerifyOrganizationDomain(idGuid);
|
|
||||||
return new OrganizationDomainResponseModel(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{orgId}/domain/{id}")]
|
|
||||||
[HttpPost("{orgId}/domain/{id}/remove")]
|
|
||||||
public async Task RemoveDomain(string orgId, string id)
|
|
||||||
{
|
|
||||||
var orgIdGuid = new Guid(orgId);
|
|
||||||
var idGuid = new Guid(id);
|
|
||||||
await ValidateOrganizationAccessAsync(orgIdGuid);
|
|
||||||
|
|
||||||
await _deleteOrganizationDomainCommand.DeleteAsync(idGuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Api.Models.Request;
|
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||||
|
using Bit.Api.Models.Request;
|
||||||
using Bit.Api.Models.Request.Organizations;
|
using Bit.Api.Models.Request.Organizations;
|
||||||
using Bit.Api.Models.Response.Organizations;
|
|
||||||
using Bit.Api.Utilities;
|
using Bit.Api.Utilities;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.Models.Request.Organizations;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Api.Models.Response.Providers;
|
using Bit.Api.AdminConsole.Models.Response;
|
||||||
|
using Bit.Api.AdminConsole.Models.Response.Providers;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
@ -13,7 +13,6 @@ public class SubscriptionResponseModel : ResponseModel
|
|||||||
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
||||||
UpcomingInvoice = subscription.UpcomingInvoice != null ?
|
UpcomingInvoice = subscription.UpcomingInvoice != null ?
|
||||||
new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
||||||
Discount = subscription.Discount != null ? new BillingCustomerDiscount(subscription.Discount) : null;
|
|
||||||
StorageName = user.Storage.HasValue ? CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
StorageName = user.Storage.HasValue ? CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
||||||
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
||||||
MaxStorageGb = user.MaxStorageGb;
|
MaxStorageGb = user.MaxStorageGb;
|
||||||
@ -41,7 +40,6 @@ public class SubscriptionResponseModel : ResponseModel
|
|||||||
public short? MaxStorageGb { get; set; }
|
public short? MaxStorageGb { get; set; }
|
||||||
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
||||||
public BillingSubscription Subscription { get; set; }
|
public BillingSubscription Subscription { get; set; }
|
||||||
public BillingCustomerDiscount Discount { get; set; }
|
|
||||||
public UserLicense License { get; set; }
|
public UserLicense License { get; set; }
|
||||||
public DateTime? Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
public bool UsingInAppPurchase { get; set; }
|
public bool UsingInAppPurchase { get; set; }
|
||||||
@ -53,10 +51,12 @@ public class BillingCustomerDiscount
|
|||||||
{
|
{
|
||||||
Id = discount.Id;
|
Id = discount.Id;
|
||||||
Active = discount.Active;
|
Active = discount.Active;
|
||||||
|
PercentOff = discount.PercentOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; }
|
||||||
public bool Active { get; set; }
|
public bool Active { get; }
|
||||||
|
public decimal? PercentOff { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BillingSubscription
|
public class BillingSubscription
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Bit.Api.Models.Response;
|
using Bit.Api.Models.Response;
|
||||||
using Bit.Api.SecretsManager.Models.Request;
|
using Bit.Api.SecretsManager.Models.Request;
|
||||||
using Bit.Api.SecretsManager.Models.Response;
|
using Bit.Api.SecretsManager.Models.Response;
|
||||||
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
using Bit.Api.Models.Response;
|
||||||
|
using Bit.Api.Utilities;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||||
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Bit.Api.SecretsManager.Controllers;
|
||||||
|
|
||||||
|
[Authorize("secrets")]
|
||||||
|
public class SecretsManagerEventsController : Controller
|
||||||
|
{
|
||||||
|
private readonly IAuthorizationService _authorizationService;
|
||||||
|
private readonly IEventRepository _eventRepository;
|
||||||
|
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||||
|
|
||||||
|
public SecretsManagerEventsController(
|
||||||
|
IEventRepository eventRepository,
|
||||||
|
IServiceAccountRepository serviceAccountRepository,
|
||||||
|
IAuthorizationService authorizationService)
|
||||||
|
{
|
||||||
|
_authorizationService = authorizationService;
|
||||||
|
_serviceAccountRepository = serviceAccountRepository;
|
||||||
|
_eventRepository = eventRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("sm/events/service-accounts/{serviceAccountId}")]
|
||||||
|
public async Task<ListResponseModel<EventResponseModel>> GetServiceAccountEventsAsync(Guid serviceAccountId,
|
||||||
|
[FromQuery] DateTime? start = null, [FromQuery] DateTime? end = null,
|
||||||
|
[FromQuery] string continuationToken = null)
|
||||||
|
{
|
||||||
|
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(serviceAccountId);
|
||||||
|
var authorizationResult =
|
||||||
|
await _authorizationService.AuthorizeAsync(User, serviceAccount, ServiceAccountOperations.ReadEvents);
|
||||||
|
|
||||||
|
if (!authorizationResult.Succeeded)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var dateRange = ApiHelpers.GetDateRange(start, end);
|
||||||
|
|
||||||
|
var result = await _eventRepository.GetManyByOrganizationServiceAccountAsync(serviceAccount.OrganizationId,
|
||||||
|
serviceAccount.Id, dateRange.Item1, dateRange.Item2,
|
||||||
|
new PageOptions { ContinuationToken = continuationToken });
|
||||||
|
var responses = result.Data.Select(e => new EventResponseModel(e));
|
||||||
|
return new ListResponseModel<EventResponseModel>(responses, result.ContinuationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Azure.Messaging.EventGrid;
|
using Azure.Messaging.EventGrid;
|
||||||
using Azure.Messaging.EventGrid.SystemEvents;
|
using Azure.Messaging.EventGrid.SystemEvents;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -69,4 +70,35 @@ public static class ApiHelpers
|
|||||||
|
|
||||||
return new OkObjectResult(response);
|
return new OkObjectResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates and returns a date range. Currently used for fetching events.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">start date and time</param>
|
||||||
|
/// <param name="end">end date and time</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// If start or end are null, will return a range of the last 30 days.
|
||||||
|
/// If a time span greater than 367 days is passed will throw BadRequestException.
|
||||||
|
/// </remarks>
|
||||||
|
public static Tuple<DateTime, DateTime> GetDateRange(DateTime? start, DateTime? end)
|
||||||
|
{
|
||||||
|
if (!end.HasValue || !start.HasValue)
|
||||||
|
{
|
||||||
|
end = DateTime.UtcNow.Date.AddDays(1).AddMilliseconds(-1);
|
||||||
|
start = DateTime.UtcNow.Date.AddDays(-30);
|
||||||
|
}
|
||||||
|
else if (start.Value > end.Value)
|
||||||
|
{
|
||||||
|
var newEnd = start;
|
||||||
|
start = end;
|
||||||
|
end = newEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((end.Value - start.Value) > TimeSpan.FromDays(367))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Range too large.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, DateTime>(start.Value, end.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json.Serialization;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Api;
|
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Core.Vault.Entities;
|
using Bit.Core.Vault.Entities;
|
||||||
@ -15,7 +14,7 @@ public class AttachmentResponseModel : ResponseModel
|
|||||||
Url = data.Url;
|
Url = data.Url;
|
||||||
FileName = data.Data.FileName;
|
FileName = data.Data.FileName;
|
||||||
Key = data.Data.Key;
|
Key = data.Data.Key;
|
||||||
Size = data.Data.Size;
|
Size = data.Data.Size.ToString();
|
||||||
SizeName = CoreHelpers.ReadableBytesSize(data.Data.Size);
|
SizeName = CoreHelpers.ReadableBytesSize(data.Data.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ public class AttachmentResponseModel : ResponseModel
|
|||||||
Url = $"{globalSettings.Attachment.BaseUrl}/{cipher.Id}/{id}";
|
Url = $"{globalSettings.Attachment.BaseUrl}/{cipher.Id}/{id}";
|
||||||
FileName = data.FileName;
|
FileName = data.FileName;
|
||||||
Key = data.Key;
|
Key = data.Key;
|
||||||
Size = data.Size;
|
Size = data.Size.ToString();
|
||||||
SizeName = CoreHelpers.ReadableBytesSize(data.Size);
|
SizeName = CoreHelpers.ReadableBytesSize(data.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +34,7 @@ public class AttachmentResponseModel : ResponseModel
|
|||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
public string Size { get; set; }
|
||||||
public long Size { get; set; }
|
|
||||||
public string SizeName { get; set; }
|
public string SizeName { get; set; }
|
||||||
|
|
||||||
public static IEnumerable<AttachmentResponseModel> FromCipher(Cipher cipher, IGlobalSettings globalSettings)
|
public static IEnumerable<AttachmentResponseModel> FromCipher(Cipher cipher, IGlobalSettings globalSettings)
|
||||||
|
@ -52,6 +52,7 @@ public class StripeController : Controller
|
|||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IStripeEventService _stripeEventService;
|
private readonly IStripeEventService _stripeEventService;
|
||||||
|
private readonly IStripeFacade _stripeFacade;
|
||||||
|
|
||||||
public StripeController(
|
public StripeController(
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
@ -70,7 +71,8 @@ public class StripeController : Controller
|
|||||||
ITaxRateRepository taxRateRepository,
|
ITaxRateRepository taxRateRepository,
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
IStripeEventService stripeEventService)
|
IStripeEventService stripeEventService,
|
||||||
|
IStripeFacade stripeFacade)
|
||||||
{
|
{
|
||||||
_billingSettings = billingSettings?.Value;
|
_billingSettings = billingSettings?.Value;
|
||||||
_hostingEnvironment = hostingEnvironment;
|
_hostingEnvironment = hostingEnvironment;
|
||||||
@ -97,6 +99,7 @@ public class StripeController : Controller
|
|||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_stripeEventService = stripeEventService;
|
_stripeEventService = stripeEventService;
|
||||||
|
_stripeFacade = stripeFacade;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("webhook")]
|
[HttpPost("webhook")]
|
||||||
@ -209,48 +212,71 @@ public class StripeController : Controller
|
|||||||
else if (parsedEvent.Type.Equals(HandledStripeWebhook.UpcomingInvoice))
|
else if (parsedEvent.Type.Equals(HandledStripeWebhook.UpcomingInvoice))
|
||||||
{
|
{
|
||||||
var invoice = await _stripeEventService.GetInvoice(parsedEvent);
|
var invoice = await _stripeEventService.GetInvoice(parsedEvent);
|
||||||
var subscriptionService = new SubscriptionService();
|
|
||||||
var subscription = await subscriptionService.GetAsync(invoice.SubscriptionId);
|
if (string.IsNullOrEmpty(invoice.SubscriptionId))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Received 'invoice.upcoming' Event with ID '{eventId}' that did not include a Subscription ID", parsedEvent.Id);
|
||||||
|
return new OkResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
var subscription = await _stripeFacade.GetSubscription(invoice.SubscriptionId);
|
||||||
|
|
||||||
if (subscription == null)
|
if (subscription == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Invoice subscription is null. " + invoice.Id);
|
throw new Exception(
|
||||||
|
$"Received null Subscription from Stripe for ID '{invoice.SubscriptionId}' while processing Event with ID '{parsedEvent.Id}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription = await VerifyCorrectTaxRateForCharge(invoice, subscription);
|
var updatedSubscription = await VerifyCorrectTaxRateForCharge(invoice, subscription);
|
||||||
|
|
||||||
string email = null;
|
var (organizationId, userId) = GetIdsFromMetaData(updatedSubscription.Metadata);
|
||||||
var ids = GetIdsFromMetaData(subscription.Metadata);
|
|
||||||
// org
|
var invoiceLineItemDescriptions = invoice.Lines.Select(i => i.Description).ToList();
|
||||||
if (ids.Item1.HasValue)
|
|
||||||
|
async Task SendEmails(IEnumerable<string> emails)
|
||||||
{
|
{
|
||||||
// sponsored org
|
var validEmails = emails.Where(e => !string.IsNullOrEmpty(e));
|
||||||
if (IsSponsoredSubscription(subscription))
|
|
||||||
|
if (invoice.NextPaymentAttempt.HasValue)
|
||||||
{
|
{
|
||||||
await _validateSponsorshipCommand.ValidateSponsorshipAsync(ids.Item1.Value);
|
await _mailService.SendInvoiceUpcoming(
|
||||||
|
validEmails,
|
||||||
|
invoice.AmountDue / 100M,
|
||||||
|
invoice.NextPaymentAttempt.Value,
|
||||||
|
invoiceLineItemDescriptions,
|
||||||
|
true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var org = await _organizationRepository.GetByIdAsync(ids.Item1.Value);
|
if (organizationId.HasValue)
|
||||||
if (org != null && OrgPlanForInvoiceNotifications(org))
|
|
||||||
{
|
{
|
||||||
email = org.BillingEmail;
|
if (IsSponsoredSubscription(updatedSubscription))
|
||||||
}
|
|
||||||
}
|
|
||||||
// user
|
|
||||||
else if (ids.Item2.HasValue)
|
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByIdAsync(ids.Item2.Value);
|
await _validateSponsorshipCommand.ValidateSponsorshipAsync(organizationId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var organization = await _organizationRepository.GetByIdAsync(organizationId.Value);
|
||||||
|
|
||||||
|
if (organization == null || !OrgPlanForInvoiceNotifications(organization))
|
||||||
|
{
|
||||||
|
return new OkResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
await SendEmails(new List<string> { organization.BillingEmail });
|
||||||
|
|
||||||
|
var ownerEmails = await _organizationRepository.GetOwnerEmailAddressesById(organization.Id);
|
||||||
|
|
||||||
|
await SendEmails(ownerEmails);
|
||||||
|
}
|
||||||
|
else if (userId.HasValue)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserByIdAsync(userId.Value);
|
||||||
|
|
||||||
if (user.Premium)
|
if (user.Premium)
|
||||||
{
|
{
|
||||||
email = user.Email;
|
await SendEmails(new List<string> { user.Email });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(email) && invoice.NextPaymentAttempt.HasValue)
|
|
||||||
{
|
|
||||||
var items = invoice.Lines.Select(i => i.Description).ToList();
|
|
||||||
await _mailService.SendInvoiceUpcomingAsync(email, invoice.AmountDue / 100M,
|
|
||||||
invoice.NextPaymentAttempt.Value, items, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (parsedEvent.Type.Equals(HandledStripeWebhook.ChargeSucceeded))
|
else if (parsedEvent.Type.Equals(HandledStripeWebhook.ChargeSucceeded))
|
||||||
{
|
{
|
||||||
|
@ -7,13 +7,16 @@ namespace Bit.Billing.Services.Implementations;
|
|||||||
public class StripeEventService : IStripeEventService
|
public class StripeEventService : IStripeEventService
|
||||||
{
|
{
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private readonly ILogger<StripeEventService> _logger;
|
||||||
private readonly IStripeFacade _stripeFacade;
|
private readonly IStripeFacade _stripeFacade;
|
||||||
|
|
||||||
public StripeEventService(
|
public StripeEventService(
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
|
ILogger<StripeEventService> logger,
|
||||||
IStripeFacade stripeFacade)
|
IStripeFacade stripeFacade)
|
||||||
{
|
{
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
|
_logger = logger;
|
||||||
_stripeFacade = stripeFacade;
|
_stripeFacade = stripeFacade;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +29,12 @@ public class StripeEventService : IStripeEventService
|
|||||||
return eventCharge;
|
return eventCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(eventCharge.Id))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot retrieve up-to-date Charge for Event with ID '{eventId}' because no Charge ID was included in the Event.", stripeEvent.Id);
|
||||||
|
return eventCharge;
|
||||||
|
}
|
||||||
|
|
||||||
var charge = await _stripeFacade.GetCharge(eventCharge.Id, new ChargeGetOptions { Expand = expand });
|
var charge = await _stripeFacade.GetCharge(eventCharge.Id, new ChargeGetOptions { Expand = expand });
|
||||||
|
|
||||||
if (charge == null)
|
if (charge == null)
|
||||||
@ -46,6 +55,12 @@ public class StripeEventService : IStripeEventService
|
|||||||
return eventCustomer;
|
return eventCustomer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(eventCustomer.Id))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot retrieve up-to-date Customer for Event with ID '{eventId}' because no Customer ID was included in the Event.", stripeEvent.Id);
|
||||||
|
return eventCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
var customer = await _stripeFacade.GetCustomer(eventCustomer.Id, new CustomerGetOptions { Expand = expand });
|
var customer = await _stripeFacade.GetCustomer(eventCustomer.Id, new CustomerGetOptions { Expand = expand });
|
||||||
|
|
||||||
if (customer == null)
|
if (customer == null)
|
||||||
@ -66,6 +81,12 @@ public class StripeEventService : IStripeEventService
|
|||||||
return eventInvoice;
|
return eventInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(eventInvoice.Id))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot retrieve up-to-date Invoice for Event with ID '{eventId}' because no Invoice ID was included in the Event.", stripeEvent.Id);
|
||||||
|
return eventInvoice;
|
||||||
|
}
|
||||||
|
|
||||||
var invoice = await _stripeFacade.GetInvoice(eventInvoice.Id, new InvoiceGetOptions { Expand = expand });
|
var invoice = await _stripeFacade.GetInvoice(eventInvoice.Id, new InvoiceGetOptions { Expand = expand });
|
||||||
|
|
||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
@ -86,6 +107,12 @@ public class StripeEventService : IStripeEventService
|
|||||||
return eventPaymentMethod;
|
return eventPaymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(eventPaymentMethod.Id))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot retrieve up-to-date Payment Method for Event with ID '{eventId}' because no Payment Method ID was included in the Event.", stripeEvent.Id);
|
||||||
|
return eventPaymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
var paymentMethod = await _stripeFacade.GetPaymentMethod(eventPaymentMethod.Id, new PaymentMethodGetOptions { Expand = expand });
|
var paymentMethod = await _stripeFacade.GetPaymentMethod(eventPaymentMethod.Id, new PaymentMethodGetOptions { Expand = expand });
|
||||||
|
|
||||||
if (paymentMethod == null)
|
if (paymentMethod == null)
|
||||||
@ -106,6 +133,12 @@ public class StripeEventService : IStripeEventService
|
|||||||
return eventSubscription;
|
return eventSubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(eventSubscription.Id))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot retrieve up-to-date Subscription for Event with ID '{eventId}' because no Subscription ID was included in the Event.", stripeEvent.Id);
|
||||||
|
return eventSubscription;
|
||||||
|
}
|
||||||
|
|
||||||
var subscription = await _stripeFacade.GetSubscription(eventSubscription.Id, new SubscriptionGetOptions { Expand = expand });
|
var subscription = await _stripeFacade.GetSubscription(eventSubscription.Id, new SubscriptionGetOptions { Expand = expand });
|
||||||
|
|
||||||
if (subscription == null)
|
if (subscription == null)
|
||||||
@ -132,7 +165,7 @@ public class StripeEventService : IStripeEventService
|
|||||||
(await GetCharge(stripeEvent, true, customerExpansion))?.Customer?.Metadata,
|
(await GetCharge(stripeEvent, true, customerExpansion))?.Customer?.Metadata,
|
||||||
|
|
||||||
HandledStripeWebhook.UpcomingInvoice =>
|
HandledStripeWebhook.UpcomingInvoice =>
|
||||||
(await GetInvoice(stripeEvent, true, customerExpansion))?.Customer?.Metadata,
|
await GetCustomerMetadataFromUpcomingInvoiceEvent(stripeEvent),
|
||||||
|
|
||||||
HandledStripeWebhook.PaymentSucceeded or HandledStripeWebhook.PaymentFailed or HandledStripeWebhook.InvoiceCreated =>
|
HandledStripeWebhook.PaymentSucceeded or HandledStripeWebhook.PaymentFailed or HandledStripeWebhook.InvoiceCreated =>
|
||||||
(await GetInvoice(stripeEvent, true, customerExpansion))?.Customer?.Metadata,
|
(await GetInvoice(stripeEvent, true, customerExpansion))?.Customer?.Metadata,
|
||||||
@ -154,6 +187,20 @@ public class StripeEventService : IStripeEventService
|
|||||||
var customerRegion = GetCustomerRegion(customerMetadata);
|
var customerRegion = GetCustomerRegion(customerMetadata);
|
||||||
|
|
||||||
return customerRegion == serverRegion;
|
return customerRegion == serverRegion;
|
||||||
|
|
||||||
|
/* In Stripe, when we receive an invoice.upcoming event, the event does not include an Invoice ID because
|
||||||
|
the invoice hasn't been created yet. Therefore, rather than retrieving the fresh Invoice with a 'customer'
|
||||||
|
expansion, we need to use the Customer ID on the event to retrieve the metadata. */
|
||||||
|
async Task<Dictionary<string, string>> GetCustomerMetadataFromUpcomingInvoiceEvent(Event localStripeEvent)
|
||||||
|
{
|
||||||
|
var invoice = await GetInvoice(localStripeEvent);
|
||||||
|
|
||||||
|
var customer = !string.IsNullOrEmpty(invoice.CustomerId)
|
||||||
|
? await _stripeFacade.GetCustomer(invoice.CustomerId)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return customer?.Metadata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T Extract<T>(Event stripeEvent)
|
private static T Extract<T>(Event stripeEvent)
|
||||||
|
@ -10,18 +10,22 @@ public class PayPalIpnClient
|
|||||||
{
|
{
|
||||||
private readonly HttpClient _httpClient = new HttpClient();
|
private readonly HttpClient _httpClient = new HttpClient();
|
||||||
private readonly Uri _ipnUri;
|
private readonly Uri _ipnUri;
|
||||||
|
private readonly ILogger<PayPalIpnClient> _logger;
|
||||||
|
|
||||||
public PayPalIpnClient(IOptions<BillingSettings> billingSettings)
|
public PayPalIpnClient(IOptions<BillingSettings> billingSettings, ILogger<PayPalIpnClient> logger)
|
||||||
{
|
{
|
||||||
var bSettings = billingSettings?.Value;
|
var bSettings = billingSettings?.Value;
|
||||||
_ipnUri = new Uri(bSettings.PayPal.Production ? "https://www.paypal.com/cgi-bin/webscr" :
|
_ipnUri = new Uri(bSettings.PayPal.Production ? "https://ipnpb.paypal.com/cgi-bin/webscr" :
|
||||||
"https://www.sandbox.paypal.com/cgi-bin/webscr");
|
"https://ipnpb.sandbox.paypal.com/cgi-bin/webscr");
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> VerifyIpnAsync(string ipnBody)
|
public async Task<bool> VerifyIpnAsync(string ipnBody)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("Verifying IPN with PayPal at {Timestamp}: {VerificationUri}", DateTime.UtcNow, _ipnUri);
|
||||||
if (ipnBody == null)
|
if (ipnBody == null)
|
||||||
{
|
{
|
||||||
|
_logger.LogError("No IPN body.");
|
||||||
throw new ArgumentException("No IPN body.");
|
throw new ArgumentException("No IPN body.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +34,7 @@ public class PayPalIpnClient
|
|||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
RequestUri = _ipnUri
|
RequestUri = _ipnUri
|
||||||
};
|
};
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("User-Agent", "CSharp-IPN-VerificationScript");
|
||||||
var cmdIpnBody = string.Concat("cmd=_notify-validate&", ipnBody);
|
var cmdIpnBody = string.Concat("cmd=_notify-validate&", ipnBody);
|
||||||
request.Content = new StringContent(cmdIpnBody, Encoding.UTF8, "application/x-www-form-urlencoded");
|
request.Content = new StringContent(cmdIpnBody, Encoding.UTF8, "application/x-www-form-urlencoded");
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
@ -42,15 +47,15 @@ public class PayPalIpnClient
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (responseContent.Equals("INVALID"))
|
|
||||||
|
if (responseContent.Equals("INVALID"))
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("Received an INVALID response from PayPal: {ResponseContent}", responseContent);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
_logger.LogError("Failed to verify IPN: {ResponseContent}", responseContent);
|
||||||
{
|
|
||||||
throw new Exception("Failed to verify IPN.");
|
throw new Exception("Failed to verify IPN.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class IpnTransaction
|
public class IpnTransaction
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Core.Entities;
|
namespace Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
public class Group : ITableObject<Guid>, IExternal
|
public class Group : ITableObject<Guid>, IExternal
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Entities;
|
namespace Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
public class GroupUser
|
public class GroupUser
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Business;
|
namespace Bit.Core.AdminConsole.Models.Business;
|
||||||
|
|
||||||
public class ImportedGroup
|
public class ImportedGroup
|
||||||
{
|
{
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user