mirror of
https://github.com/bitwarden/server
synced 2026-01-19 17:03:16 +00:00
Merge branch 'master' into feature/billing-obfuscation
This commit is contained in:
@@ -35,7 +35,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Admin.dll
|
||||
|
||||
@@ -4,6 +4,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -130,6 +131,14 @@ public class DevicesController : Controller
|
||||
await _deviceService.DeleteAsync(device);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("knowndevice")]
|
||||
public async Task<bool> GetByIdentifierQuery(
|
||||
[FromHeader(Name = "X-Request-Email")] string email,
|
||||
[FromHeader(Name = "X-Device-Identifier")] string deviceIdentifier)
|
||||
=> await GetByIdentifier(CoreHelpers.Base64UrlDecodeString(email), deviceIdentifier);
|
||||
|
||||
[Obsolete("Path is deprecated due to encoding issues, use /knowndevice instead.")]
|
||||
[AllowAnonymous]
|
||||
[HttpGet("knowndevice/{email}/{identifier}")]
|
||||
public async Task<bool> GetByIdentifier(string email, string identifier)
|
||||
|
||||
@@ -5,7 +5,6 @@ using Bit.Api.Models.Request.Organizations;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Api.Models.Response.Organizations;
|
||||
using Bit.Api.SecretsManager;
|
||||
using Bit.Api.Utilities;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@@ -225,28 +224,6 @@ public class OrganizationsController : Controller
|
||||
return new OrganizationResponseModel(result.Item1);
|
||||
}
|
||||
|
||||
[Obsolete("2022-12-7 Moved to SelfHostedOrganizationLicensesController, to be removed in EC-815")]
|
||||
[HttpPost("license")]
|
||||
[SelfHosted(SelfHostedOnly = true)]
|
||||
public async Task<OrganizationResponseModel> PostLicense(OrganizationCreateLicenseRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(HttpContext, model.License);
|
||||
if (license == null)
|
||||
{
|
||||
throw new BadRequestException("Invalid license");
|
||||
}
|
||||
|
||||
var result = await _organizationService.SignUpAsync(license, user, model.Key,
|
||||
model.CollectionName, model.Keys?.PublicKey, model.Keys?.EncryptedPrivateKey);
|
||||
return new OrganizationResponseModel(result.Item1);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[HttpPost("{id}")]
|
||||
public async Task<OrganizationResponseModel> Put(string id, [FromBody] OrganizationUpdateRequestModel model)
|
||||
@@ -447,34 +424,6 @@ public class OrganizationsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("2022-12-7 Moved to SelfHostedOrganizationLicensesController, to be removed in EC-815")]
|
||||
[HttpPost("{id}/license")]
|
||||
[SelfHosted(SelfHostedOnly = true)]
|
||||
public async Task PostLicense(string id, LicenseRequestModel model)
|
||||
{
|
||||
var orgIdGuid = new Guid(id);
|
||||
if (!await _currentContext.OrganizationOwner(orgIdGuid))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(HttpContext, model.License);
|
||||
if (license == null)
|
||||
{
|
||||
throw new BadRequestException("Invalid license");
|
||||
}
|
||||
|
||||
var selfHostedOrganizationDetails = await _organizationRepository.GetSelfHostedOrganizationDetailsById(orgIdGuid);
|
||||
if (selfHostedOrganizationDetails == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var existingOrganization = await _organizationRepository.GetByLicenseKeyAsync(license.LicenseKey);
|
||||
|
||||
await _updateOrganizationLicenseCommand.UpdateLicenseAsync(selfHostedOrganizationDetails, license, existingOrganization);
|
||||
}
|
||||
|
||||
[HttpPost("{id}/import")]
|
||||
public async Task Import(string id, [FromBody] ImportOrganizationUsersRequestModel model)
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ public class AccessPoliciesController : Controller
|
||||
var (accessClient, userId) = await GetAccessClientTypeAsync(project.OrganizationId);
|
||||
var policies = request.ToBaseAccessPoliciesForProject(id);
|
||||
await _createAccessPoliciesCommand.CreateManyAsync(policies, userId, accessClient);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(id);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(id, userId);
|
||||
return new ProjectAccessPoliciesResponseModel(results);
|
||||
}
|
||||
|
||||
@@ -81,9 +81,8 @@ public class AccessPoliciesController : Controller
|
||||
public async Task<ProjectAccessPoliciesResponseModel> GetProjectAccessPoliciesAsync([FromRoute] Guid id)
|
||||
{
|
||||
var project = await _projectRepository.GetByIdAsync(id);
|
||||
await CheckUserHasWriteAccessToProjectAsync(project);
|
||||
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(id);
|
||||
var (_, userId) = await CheckUserHasWriteAccessToProjectAsync(project);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(id, userId);
|
||||
return new ProjectAccessPoliciesResponseModel(results);
|
||||
}
|
||||
|
||||
@@ -106,7 +105,7 @@ public class AccessPoliciesController : Controller
|
||||
var (accessClient, userId) = await GetAccessClientTypeAsync(serviceAccount.OrganizationId);
|
||||
var policies = request.ToBaseAccessPoliciesForServiceAccount(id);
|
||||
await _createAccessPoliciesCommand.CreateManyAsync(policies, userId, accessClient);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedServiceAccountIdAsync(id);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedServiceAccountIdAsync(id, userId);
|
||||
return new ServiceAccountAccessPoliciesResponseModel(results);
|
||||
}
|
||||
|
||||
@@ -115,9 +114,8 @@ public class AccessPoliciesController : Controller
|
||||
[FromRoute] Guid id)
|
||||
{
|
||||
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(id);
|
||||
await CheckUserHasWriteAccessToServiceAccountAsync(serviceAccount);
|
||||
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedServiceAccountIdAsync(id);
|
||||
var (_, userId) = await CheckUserHasWriteAccessToServiceAccountAsync(serviceAccount);
|
||||
var results = await _accessPolicyRepository.GetManyByGrantedServiceAccountIdAsync(id, userId);
|
||||
return new ServiceAccountAccessPoliciesResponseModel(results);
|
||||
}
|
||||
|
||||
@@ -206,7 +204,7 @@ public class AccessPoliciesController : Controller
|
||||
var organizationUsers =
|
||||
await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
|
||||
var userResponses = organizationUsers
|
||||
.Where(user => user.AccessSecretsManager)
|
||||
.Where(user => user.AccessSecretsManager && user.Status == OrganizationUserStatusType.Confirmed)
|
||||
.Select(userDetails => new PotentialGranteeResponseModel(userDetails));
|
||||
|
||||
return new ListResponseModel<PotentialGranteeResponseModel>(userResponses.Concat(groupResponses));
|
||||
@@ -244,7 +242,7 @@ public class AccessPoliciesController : Controller
|
||||
return new ListResponseModel<PotentialGranteeResponseModel>(projectResponses);
|
||||
}
|
||||
|
||||
private async Task CheckUserHasWriteAccessToProjectAsync(Project project)
|
||||
private async Task<(AccessClientType AccessClientType, Guid UserId)> CheckUserHasWriteAccessToProjectAsync(Project project)
|
||||
{
|
||||
if (project == null)
|
||||
{
|
||||
@@ -263,9 +261,10 @@ public class AccessPoliciesController : Controller
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return (accessClient, userId);
|
||||
}
|
||||
|
||||
private async Task CheckUserHasWriteAccessToServiceAccountAsync(ServiceAccount serviceAccount)
|
||||
private async Task<(AccessClientType AccessClientType, Guid UserId)> CheckUserHasWriteAccessToServiceAccountAsync(ServiceAccount serviceAccount)
|
||||
{
|
||||
if (serviceAccount == null)
|
||||
{
|
||||
@@ -285,6 +284,7 @@ public class AccessPoliciesController : Controller
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return (accessClient, userId);
|
||||
}
|
||||
|
||||
private async Task<(AccessClientType AccessClientType, Guid UserId)> GetAccessClientTypeAsync(Guid organizationId)
|
||||
|
||||
@@ -61,6 +61,11 @@ public class SecretsManagerPortingController : Controller
|
||||
throw new BadRequestException("You cannot import this much data at once, the limit is 1000 projects and 6000 secrets.");
|
||||
}
|
||||
|
||||
if (importRequest.Secrets.Any(s => s.ProjectIds.Count() > 1))
|
||||
{
|
||||
throw new BadRequestException("A secret can only be in one project at a time.");
|
||||
}
|
||||
|
||||
await _importCommand.ImportAsync(organizationId, importRequest.ToSMImport());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class ServiceAccountsController : Controller
|
||||
private readonly ICreateAccessTokenCommand _createAccessTokenCommand;
|
||||
private readonly ICreateServiceAccountCommand _createServiceAccountCommand;
|
||||
private readonly IUpdateServiceAccountCommand _updateServiceAccountCommand;
|
||||
private readonly IDeleteServiceAccountsCommand _deleteServiceAccountsCommand;
|
||||
private readonly IRevokeAccessTokensCommand _revokeAccessTokensCommand;
|
||||
|
||||
public ServiceAccountsController(
|
||||
@@ -35,6 +36,7 @@ public class ServiceAccountsController : Controller
|
||||
ICreateAccessTokenCommand createAccessTokenCommand,
|
||||
ICreateServiceAccountCommand createServiceAccountCommand,
|
||||
IUpdateServiceAccountCommand updateServiceAccountCommand,
|
||||
IDeleteServiceAccountsCommand deleteServiceAccountsCommand,
|
||||
IRevokeAccessTokensCommand revokeAccessTokensCommand)
|
||||
{
|
||||
_currentContext = currentContext;
|
||||
@@ -43,6 +45,7 @@ public class ServiceAccountsController : Controller
|
||||
_apiKeyRepository = apiKeyRepository;
|
||||
_createServiceAccountCommand = createServiceAccountCommand;
|
||||
_updateServiceAccountCommand = updateServiceAccountCommand;
|
||||
_deleteServiceAccountsCommand = deleteServiceAccountsCommand;
|
||||
_revokeAccessTokensCommand = revokeAccessTokensCommand;
|
||||
_createAccessTokenCommand = createAccessTokenCommand;
|
||||
}
|
||||
@@ -67,6 +70,41 @@ public class ServiceAccountsController : Controller
|
||||
return new ListResponseModel<ServiceAccountResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ServiceAccountResponseModel> GetByServiceAccountIdAsync(
|
||||
[FromRoute] Guid id)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(id);
|
||||
|
||||
if (serviceAccount == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (!_currentContext.AccessSecretsManager(serviceAccount.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var orgAdmin = await _currentContext.OrganizationAdmin(serviceAccount.OrganizationId);
|
||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||
|
||||
var hasAccess = accessClient switch
|
||||
{
|
||||
AccessClientType.NoAccessCheck => true,
|
||||
AccessClientType.User => await _serviceAccountRepository.UserHasWriteAccessToServiceAccount(id, userId),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if (!hasAccess)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new ServiceAccountResponseModel(serviceAccount);
|
||||
}
|
||||
|
||||
[HttpPost("/organizations/{organizationId}/service-accounts")]
|
||||
public async Task<ServiceAccountResponseModel> CreateAsync([FromRoute] Guid organizationId,
|
||||
[FromBody] ServiceAccountCreateRequestModel createRequest)
|
||||
@@ -90,6 +128,16 @@ public class ServiceAccountsController : Controller
|
||||
return new ServiceAccountResponseModel(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete")]
|
||||
public async Task<ListResponseModel<BulkDeleteResponseModel>> BulkDeleteAsync([FromBody] List<Guid> ids)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
var results = await _deleteServiceAccountsCommand.DeleteServiceAccounts(ids, userId);
|
||||
var responses = results.Select(r => new BulkDeleteResponseModel(r.Item1.Id, r.Item2));
|
||||
return new ListResponseModel<BulkDeleteResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpGet("{id}/access-tokens")]
|
||||
public async Task<ListResponseModel<AccessTokenResponseModel>> GetAccessTokens([FromRoute] Guid id)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@ public class UserProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMode
|
||||
OrganizationUserId = accessPolicy.OrganizationUserId;
|
||||
GrantedProjectId = accessPolicy.GrantedProjectId;
|
||||
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
|
||||
UserId = accessPolicy.User?.Id;
|
||||
}
|
||||
|
||||
public UserProjectAccessPolicyResponseModel() : base(new UserProjectAccessPolicy(), _objectName)
|
||||
@@ -45,6 +46,7 @@ public class UserProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMode
|
||||
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public string? OrganizationUserName { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? GrantedProjectId { get; set; }
|
||||
}
|
||||
|
||||
@@ -58,6 +60,7 @@ public class UserServiceAccountAccessPolicyResponseModel : BaseAccessPolicyRespo
|
||||
OrganizationUserId = accessPolicy.OrganizationUserId;
|
||||
GrantedServiceAccountId = accessPolicy.GrantedServiceAccountId;
|
||||
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
|
||||
UserId = accessPolicy.User?.Id;
|
||||
}
|
||||
|
||||
public UserServiceAccountAccessPolicyResponseModel() : base(new UserServiceAccountAccessPolicy(), _objectName)
|
||||
@@ -66,6 +69,7 @@ public class UserServiceAccountAccessPolicyResponseModel : BaseAccessPolicyRespo
|
||||
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public string? OrganizationUserName { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? GrantedServiceAccountId { get; set; }
|
||||
}
|
||||
|
||||
@@ -79,6 +83,7 @@ public class GroupProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMod
|
||||
GroupId = accessPolicy.GroupId;
|
||||
GrantedProjectId = accessPolicy.GrantedProjectId;
|
||||
GroupName = accessPolicy.Group?.Name;
|
||||
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
|
||||
}
|
||||
|
||||
public GroupProjectAccessPolicyResponseModel() : base(new GroupProjectAccessPolicy(), _objectName)
|
||||
@@ -87,6 +92,7 @@ public class GroupProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMod
|
||||
|
||||
public Guid? GroupId { get; set; }
|
||||
public string? GroupName { get; set; }
|
||||
public bool? CurrentUserInGroup { get; set; }
|
||||
public Guid? GrantedProjectId { get; set; }
|
||||
}
|
||||
|
||||
@@ -100,6 +106,7 @@ public class GroupServiceAccountAccessPolicyResponseModel : BaseAccessPolicyResp
|
||||
GroupId = accessPolicy.GroupId;
|
||||
GroupName = accessPolicy.Group?.Name;
|
||||
GrantedServiceAccountId = accessPolicy.GrantedServiceAccountId;
|
||||
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
|
||||
}
|
||||
|
||||
public GroupServiceAccountAccessPolicyResponseModel() : base(new GroupServiceAccountAccessPolicy(), _objectName)
|
||||
@@ -109,6 +116,7 @@ public class GroupServiceAccountAccessPolicyResponseModel : BaseAccessPolicyResp
|
||||
public Guid? GroupId { get; set; }
|
||||
public string? GroupName { get; set; }
|
||||
public Guid? GrantedServiceAccountId { get; set; }
|
||||
public bool? CurrentUserInGroup { get; set; }
|
||||
}
|
||||
|
||||
public class ServiceAccountProjectAccessPolicyResponseModel : BaseAccessPolicyResponseModel
|
||||
|
||||
@@ -35,7 +35,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Api.dll
|
||||
|
||||
@@ -147,7 +147,7 @@ public class FreshdeskController : Controller
|
||||
{
|
||||
var freshdeskAuthkey = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_billingSettings.FreshdeskApiKey}:X"));
|
||||
var httpClient = _httpClientFactory.CreateClient("FreshdeskApi");
|
||||
request.Headers.Add("Authorization", freshdeskAuthkey);
|
||||
request.Headers.Add("Authorization", $"Basic {freshdeskAuthkey}");
|
||||
var response = await httpClient.SendAsync(request);
|
||||
if (response.StatusCode != System.Net.HttpStatusCode.TooManyRequests || retriedCount > 3)
|
||||
{
|
||||
|
||||
@@ -35,7 +35,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Billing.dll
|
||||
|
||||
@@ -22,3 +22,8 @@ public static class AuthenticationSchemes
|
||||
{
|
||||
public const string BitwardenExternalCookieAuthenticationScheme = "bw.external";
|
||||
}
|
||||
|
||||
public static class FeatureFlagKeys
|
||||
{
|
||||
public const string SecretsManager = "secrets-manager";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
||||
|
||||
public interface IDeleteServiceAccountsCommand
|
||||
{
|
||||
Task<List<Tuple<ServiceAccount, string>>> DeleteServiceAccounts(List<Guid> ids, Guid userId);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class GroupProjectAccessPolicy : BaseAccessPolicy
|
||||
{
|
||||
public Guid? GroupId { get; set; }
|
||||
public Group? Group { get; set; }
|
||||
public bool? CurrentUserInGroup { get; set; }
|
||||
public Guid? GrantedProjectId { get; set; }
|
||||
public Project? GrantedProject { get; set; }
|
||||
}
|
||||
@@ -49,6 +50,7 @@ public class GroupServiceAccountAccessPolicy : BaseAccessPolicy
|
||||
{
|
||||
public Guid? GroupId { get; set; }
|
||||
public Group? Group { get; set; }
|
||||
public bool? CurrentUserInGroup { get; set; }
|
||||
public Guid? GrantedServiceAccountId { get; set; }
|
||||
public ServiceAccount? GrantedServiceAccount { get; set; }
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ public interface IAccessPolicyRepository
|
||||
Task<List<BaseAccessPolicy>> CreateManyAsync(List<BaseAccessPolicy> baseAccessPolicies);
|
||||
Task<bool> AccessPolicyExists(BaseAccessPolicy baseAccessPolicy);
|
||||
Task<BaseAccessPolicy?> GetByIdAsync(Guid id);
|
||||
Task<IEnumerable<BaseAccessPolicy>> GetManyByGrantedProjectIdAsync(Guid id);
|
||||
Task<IEnumerable<BaseAccessPolicy>> GetManyByGrantedServiceAccountIdAsync(Guid id);
|
||||
Task<IEnumerable<BaseAccessPolicy>> GetManyByGrantedProjectIdAsync(Guid id, Guid userId);
|
||||
Task<IEnumerable<BaseAccessPolicy>> GetManyByGrantedServiceAccountIdAsync(Guid id, Guid userId);
|
||||
Task<IEnumerable<BaseAccessPolicy>> GetManyByServiceAccountIdAsync(Guid id, Guid userId,
|
||||
AccessClientType accessType);
|
||||
Task ReplaceAsync(BaseAccessPolicy baseAccessPolicy);
|
||||
|
||||
@@ -7,8 +7,10 @@ public interface IServiceAccountRepository
|
||||
{
|
||||
Task<IEnumerable<ServiceAccount>> GetManyByOrganizationIdAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||
Task<ServiceAccount> GetByIdAsync(Guid id);
|
||||
Task<IEnumerable<ServiceAccount>> GetManyByIds(IEnumerable<Guid> ids);
|
||||
Task<ServiceAccount> CreateAsync(ServiceAccount serviceAccount);
|
||||
Task ReplaceAsync(ServiceAccount serviceAccount);
|
||||
Task DeleteManyByIdAsync(IEnumerable<Guid> ids);
|
||||
Task<bool> UserHasReadAccessToServiceAccount(Guid id, Guid userId);
|
||||
Task<bool> UserHasWriteAccessToServiceAccount(Guid id, Guid userId);
|
||||
Task<IEnumerable<ServiceAccount>> GetManyByOrganizationIdWriteAccessAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||
|
||||
@@ -1,6 +1,39 @@
|
||||
namespace Bit.Core.Services;
|
||||
using Bit.Core.Context;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public interface IFeatureService
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks whether online access to feature status is available.
|
||||
/// </summary>
|
||||
/// <returns>True if the service is online, otherwise false.</returns>
|
||||
bool IsOnline();
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a given feature is enabled.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate whether a feature should be on or off.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>True if the feature is enabled, otherwise false.</returns>
|
||||
bool IsEnabled(string key, ICurrentContext currentContext, bool defaultValue = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the integer variation of a feature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate the feature value.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>The feature variation value.</returns>
|
||||
int GetIntVariation(string key, ICurrentContext currentContext, int defaultValue = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string variation of a feature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate the feature value.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>The feature variation value.</returns>
|
||||
string GetStringVariation(string key, ICurrentContext currentContext, string defaultValue = null);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Settings;
|
||||
using LaunchDarkly.Sdk.Server;
|
||||
using LaunchDarkly.Sdk.Server.Integrations;
|
||||
|
||||
@@ -47,8 +48,44 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
return _client.Initialized && !_client.IsOffline();
|
||||
}
|
||||
|
||||
public bool IsEnabled(string key, ICurrentContext currentContext, bool defaultValue = false)
|
||||
{
|
||||
return _client.BoolVariation(key, BuildContext(currentContext), defaultValue);
|
||||
}
|
||||
|
||||
public int GetIntVariation(string key, ICurrentContext currentContext, int defaultValue = 0)
|
||||
{
|
||||
return _client.IntVariation(key, BuildContext(currentContext), defaultValue);
|
||||
}
|
||||
|
||||
public string GetStringVariation(string key, ICurrentContext currentContext, string defaultValue = null)
|
||||
{
|
||||
return _client.StringVariation(key, BuildContext(currentContext), defaultValue);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client?.Dispose();
|
||||
}
|
||||
|
||||
private LaunchDarkly.Sdk.Context BuildContext(ICurrentContext currentContext)
|
||||
{
|
||||
var builder = LaunchDarkly.Sdk.Context.MultiBuilder();
|
||||
|
||||
if (currentContext.UserId.HasValue)
|
||||
{
|
||||
var user = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString());
|
||||
user.Kind(LaunchDarkly.Sdk.ContextKind.Default);
|
||||
builder.Add(user.Build());
|
||||
}
|
||||
|
||||
if (currentContext.OrganizationId.HasValue)
|
||||
{
|
||||
var org = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString());
|
||||
org.Kind("org");
|
||||
builder.Add(org.Build());
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Events.dll
|
||||
|
||||
@@ -34,7 +34,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
#mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
#cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
# && update-ca-certificates
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/EventsProcessor.dll
|
||||
|
||||
@@ -34,7 +34,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Icons.dll
|
||||
|
||||
@@ -35,10 +35,15 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/identity/identity.pfx /app/identity.pfx
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/identity/identity.pfx /app/identity.pfx
|
||||
fi
|
||||
|
||||
chown -R $USERNAME:$GROUPNAME /app
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Identity.dll
|
||||
|
||||
@@ -186,13 +186,13 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var groups =
|
||||
from cg in dbContext.CollectionGroups
|
||||
where cg.Collection.OrganizationId == organizationId
|
||||
from c in collections
|
||||
join cg in dbContext.CollectionGroups on c.Id equals cg.CollectionId
|
||||
group cg by cg.CollectionId into g
|
||||
select g;
|
||||
var users =
|
||||
from cu in dbContext.CollectionUsers
|
||||
where cu.Collection.OrganizationId == organizationId
|
||||
from c in collections
|
||||
join cu in dbContext.CollectionUsers on c.Id equals cu.CollectionId
|
||||
group cu by cu.CollectionId into u
|
||||
select u;
|
||||
|
||||
@@ -230,19 +230,16 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var groups =
|
||||
from cg in dbContext.CollectionGroups
|
||||
where cg.Collection.OrganizationId == organizationId
|
||||
&& collections.Select(c => c.Id).Contains(cg.Collection.Id)
|
||||
from c in collections
|
||||
join cg in dbContext.CollectionGroups on c.Id equals cg.CollectionId
|
||||
group cg by cg.CollectionId into g
|
||||
select g;
|
||||
var users =
|
||||
from cu in dbContext.CollectionUsers
|
||||
where cu.Collection.OrganizationId == organizationId
|
||||
&& collections.Select(c => c.Id).Contains(cu.Collection.Id)
|
||||
from c in collections
|
||||
join cu in dbContext.CollectionUsers on c.Id equals cu.CollectionId
|
||||
group cu by cu.CollectionId into u
|
||||
select u;
|
||||
|
||||
|
||||
return collections.Select(collection =>
|
||||
new Tuple<Core.Entities.Collection, CollectionAccessDetails>(
|
||||
collection,
|
||||
|
||||
@@ -34,7 +34,9 @@ mkdir -p /etc/bitwarden/logs
|
||||
mkdir -p /etc/bitwarden/ca-certificates
|
||||
chown -R $USERNAME:$GROUPNAME /etc/bitwarden
|
||||
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
if [[ $globalSettings__selfHosted == "true" ]]; then
|
||||
cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \
|
||||
&& update-ca-certificates
|
||||
fi
|
||||
|
||||
exec gosu $USERNAME:$GROUPNAME dotnet /app/Notifications.dll
|
||||
|
||||
Reference in New Issue
Block a user