mirror of
https://github.com/bitwarden/server
synced 2026-02-04 18:53:28 +00:00
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
This commit is contained in:
@@ -57,8 +57,7 @@ public class ProviderClientsController(
|
||||
Owner = user,
|
||||
BillingEmail = provider.BillingEmail,
|
||||
OwnerKey = requestBody.Key,
|
||||
PublicKey = requestBody.KeyPair.PublicKey,
|
||||
PrivateKey = requestBody.KeyPair.EncryptedPrivateKey,
|
||||
Keys = requestBody.KeyPair.ToPublicKeyEncryptionKeyPairData(),
|
||||
CollectionName = requestBody.CollectionName,
|
||||
IsFromProvider = true
|
||||
};
|
||||
|
||||
@@ -113,11 +113,10 @@ public class OrganizationCreateRequestModel : IValidatableObject
|
||||
BillingAddressCountry = BillingAddressCountry,
|
||||
},
|
||||
InitiationPath = InitiationPath,
|
||||
SkipTrial = SkipTrial
|
||||
SkipTrial = SkipTrial,
|
||||
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
|
||||
};
|
||||
|
||||
Keys?.ToOrganizationSignup(orgSignup);
|
||||
|
||||
return orgSignup;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
|
||||
@@ -14,48 +13,10 @@ public class OrganizationKeysRequestModel
|
||||
[Required]
|
||||
public string EncryptedPrivateKey { get; set; }
|
||||
|
||||
public OrganizationSignup ToOrganizationSignup(OrganizationSignup existingSignup)
|
||||
public PublicKeyEncryptionKeyPairData ToPublicKeyEncryptionKeyPairData()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(existingSignup.PublicKey))
|
||||
{
|
||||
existingSignup.PublicKey = PublicKey;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existingSignup.PrivateKey))
|
||||
{
|
||||
existingSignup.PrivateKey = EncryptedPrivateKey;
|
||||
}
|
||||
|
||||
return existingSignup;
|
||||
}
|
||||
|
||||
public OrganizationUpgrade ToOrganizationUpgrade(OrganizationUpgrade existingUpgrade)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(existingUpgrade.PublicKey))
|
||||
{
|
||||
existingUpgrade.PublicKey = PublicKey;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existingUpgrade.PrivateKey))
|
||||
{
|
||||
existingUpgrade.PrivateKey = EncryptedPrivateKey;
|
||||
}
|
||||
|
||||
return existingUpgrade;
|
||||
}
|
||||
|
||||
public Organization ToOrganization(Organization existingOrg)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(existingOrg.PublicKey))
|
||||
{
|
||||
existingOrg.PublicKey = PublicKey;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existingOrg.PrivateKey))
|
||||
{
|
||||
existingOrg.PrivateKey = EncryptedPrivateKey;
|
||||
}
|
||||
|
||||
return existingOrg;
|
||||
return new PublicKeyEncryptionKeyPairData(
|
||||
wrappedPrivateKey: EncryptedPrivateKey,
|
||||
publicKey: PublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +110,9 @@ public class OrganizationNoPaymentCreateRequest
|
||||
BillingAddressCountry = BillingAddressCountry,
|
||||
},
|
||||
InitiationPath = InitiationPath,
|
||||
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
|
||||
};
|
||||
|
||||
Keys?.ToOrganizationSignup(orgSignup);
|
||||
|
||||
return orgSignup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ public class OrganizationUpdateRequestModel
|
||||
OrganizationId = organizationId,
|
||||
Name = Name,
|
||||
BillingEmail = BillingEmail,
|
||||
PublicKey = Keys?.PublicKey,
|
||||
EncryptedPrivateKey = Keys?.EncryptedPrivateKey
|
||||
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,11 +43,10 @@ public class OrganizationUpgradeRequestModel
|
||||
{
|
||||
BillingAddressCountry = BillingAddressCountry,
|
||||
BillingAddressPostalCode = BillingAddressPostalCode
|
||||
}
|
||||
},
|
||||
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
|
||||
};
|
||||
|
||||
Keys?.ToOrganizationUpgrade(orgUpgrade);
|
||||
|
||||
return orgUpgrade;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.31.0" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ using Microsoft.AspNetCore.Mvc;
|
||||
namespace Bit.Api.Auth.Controllers;
|
||||
|
||||
[Route("webauthn")]
|
||||
[Authorize(Policies.Web)]
|
||||
public class WebAuthnController : Controller
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
@@ -62,6 +61,7 @@ public class WebAuthnController : Controller
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
[Authorize(Policies.Web)]
|
||||
[HttpGet("")]
|
||||
public async Task<ListResponseModel<WebAuthnCredentialResponseModel>> Get()
|
||||
{
|
||||
@@ -71,6 +71,7 @@ public class WebAuthnController : Controller
|
||||
return new ListResponseModel<WebAuthnCredentialResponseModel>(credentials.Select(c => new WebAuthnCredentialResponseModel(c)));
|
||||
}
|
||||
|
||||
[Authorize(Policies.Application)]
|
||||
[HttpPost("attestation-options")]
|
||||
public async Task<WebAuthnCredentialCreateOptionsResponseModel> AttestationOptions([FromBody] SecretVerificationRequestModel model)
|
||||
{
|
||||
@@ -88,6 +89,7 @@ public class WebAuthnController : Controller
|
||||
};
|
||||
}
|
||||
|
||||
[Authorize(Policies.Web)]
|
||||
[HttpPost("assertion-options")]
|
||||
public async Task<WebAuthnLoginAssertionOptionsResponseModel> AssertionOptions([FromBody] SecretVerificationRequestModel model)
|
||||
{
|
||||
@@ -104,6 +106,7 @@ public class WebAuthnController : Controller
|
||||
};
|
||||
}
|
||||
|
||||
[Authorize(Policies.Application)]
|
||||
[HttpPost("")]
|
||||
public async Task Post([FromBody] WebAuthnLoginCredentialCreateRequestModel model)
|
||||
{
|
||||
@@ -149,6 +152,7 @@ public class WebAuthnController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize(Policies.Application)]
|
||||
[HttpPut()]
|
||||
public async Task UpdateCredential([FromBody] WebAuthnLoginCredentialUpdateRequestModel model)
|
||||
{
|
||||
@@ -172,6 +176,7 @@ public class WebAuthnController : Controller
|
||||
await _credentialRepository.UpdateAsync(credential);
|
||||
}
|
||||
|
||||
[Authorize(Policies.Web)]
|
||||
[HttpPost("{id}/delete")]
|
||||
public async Task Delete(Guid id, [FromBody] SecretVerificationRequestModel model)
|
||||
{
|
||||
|
||||
@@ -273,7 +273,7 @@ public class TwoFactorWebAuthnDeleteRequestModel : SecretVerificationRequestMode
|
||||
yield return validationResult;
|
||||
}
|
||||
|
||||
if (!Id.HasValue || Id < 0 || Id > 5)
|
||||
if (!Id.HasValue)
|
||||
{
|
||||
yield return new ValidationResult("Invalid Key Id", new string[] { nameof(Id) });
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Bit.Api.Billing.Models.Requests.Payment;
|
||||
using Bit.Api.Billing.Models.Requests.Premium;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Billing.Licenses.Queries;
|
||||
using Bit.Core.Billing.Payment.Commands;
|
||||
using Bit.Core.Billing.Payment.Queries;
|
||||
using Bit.Core.Billing.Premium.Commands;
|
||||
@@ -21,6 +22,7 @@ public class AccountBillingVNextController(
|
||||
ICreatePremiumCloudHostedSubscriptionCommand createPremiumCloudHostedSubscriptionCommand,
|
||||
IGetCreditQuery getCreditQuery,
|
||||
IGetPaymentMethodQuery getPaymentMethodQuery,
|
||||
IGetUserLicenseQuery getUserLicenseQuery,
|
||||
IUpdatePaymentMethodCommand updatePaymentMethodCommand) : BaseBillingController
|
||||
{
|
||||
[HttpGet("credit")]
|
||||
@@ -77,4 +79,13 @@ public class AccountBillingVNextController(
|
||||
user, paymentMethod, billingAddress, additionalStorageGb);
|
||||
return Handle(result);
|
||||
}
|
||||
|
||||
[HttpGet("license")]
|
||||
[InjectUser]
|
||||
public async Task<IResult> GetLicenseAsync(
|
||||
[BindNever] User user)
|
||||
{
|
||||
var response = await getUserLicenseQuery.Run(user);
|
||||
return TypedResults.Ok(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Api.Billing.Models.Requests;
|
||||
|
||||
@@ -12,4 +13,11 @@ public class KeyPairRequestBody
|
||||
public string PublicKey { get; set; }
|
||||
[Required(ErrorMessage = "'encryptedPrivateKey' must be provided")]
|
||||
public string EncryptedPrivateKey { get; set; }
|
||||
|
||||
public PublicKeyEncryptionKeyPairData ToPublicKeyEncryptionKeyPairData()
|
||||
{
|
||||
return new PublicKeyEncryptionKeyPairData(
|
||||
wrappedPrivateKey: EncryptedPrivateKey,
|
||||
publicKey: PublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Api.Dirt.Models.Request;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Exceptions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Dirt.Controllers;
|
||||
|
||||
[Route("organizations/{organizationId:guid}/integrations/{integrationId:guid}/configurations")]
|
||||
[Authorize("Application")]
|
||||
@@ -1,12 +1,12 @@
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Api.Dirt.Models.Request;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Exceptions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Dirt.Controllers;
|
||||
|
||||
[Route("organizations/{organizationId:guid}/integrations")]
|
||||
[Authorize("Application")]
|
||||
@@ -1,16 +1,16 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Dirt.Controllers;
|
||||
|
||||
[Route("organizations")]
|
||||
[Authorize("Application")]
|
||||
@@ -1,18 +1,18 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Bot.Builder;
|
||||
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Controllers;
|
||||
namespace Bit.Api.Dirt.Controllers;
|
||||
|
||||
[Route("organizations")]
|
||||
[Authorize("Application")]
|
||||
@@ -1,8 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
namespace Bit.Api.Dirt.Models.Request;
|
||||
|
||||
public class OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
namespace Bit.Api.Dirt.Models.Request;
|
||||
|
||||
public class OrganizationIntegrationRequestModel : IValidatableObject
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
namespace Bit.Api.Dirt.Models.Response;
|
||||
|
||||
public class OrganizationIntegrationConfigurationResponseModel : ResponseModel
|
||||
{
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
namespace Bit.Api.Dirt.Models.Response;
|
||||
|
||||
public class OrganizationIntegrationResponseModel : ResponseModel
|
||||
{
|
||||
@@ -44,7 +44,7 @@ public class SendRotationValidator : IRotationValidator<IEnumerable<SendWithIdRe
|
||||
throw new BadRequestException("All existing sends must be included in the rotation.");
|
||||
}
|
||||
|
||||
result.Add(send.ToSend(existing, _sendAuthorizationService));
|
||||
result.Add(send.UpdateSend(existing, _sendAuthorizationService));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
using Bit.Core;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Services;
|
||||
@@ -45,7 +46,8 @@ public class ConfigResponseModel : ResponseModel
|
||||
Sso = globalSettings.BaseServiceUri.Sso
|
||||
};
|
||||
FeatureStates = featureService.GetAll();
|
||||
Push = PushSettings.Build(globalSettings);
|
||||
var webPushEnabled = FeatureStates.TryGetValue(FeatureFlagKeys.WebPush, out var webPushEnabledValue) ? (bool)webPushEnabledValue : false;
|
||||
Push = PushSettings.Build(webPushEnabled, globalSettings);
|
||||
Settings = new ServerSettingsResponseModel
|
||||
{
|
||||
DisableUserRegistration = globalSettings.DisableUserRegistration
|
||||
@@ -74,9 +76,9 @@ public class PushSettings
|
||||
public PushTechnologyType PushTechnology { get; private init; }
|
||||
public string VapidPublicKey { get; private init; }
|
||||
|
||||
public static PushSettings Build(IGlobalSettings globalSettings)
|
||||
public static PushSettings Build(bool webPushEnabled, IGlobalSettings globalSettings)
|
||||
{
|
||||
var vapidPublicKey = globalSettings.WebPush.VapidPublicKey;
|
||||
var vapidPublicKey = webPushEnabled ? globalSettings.WebPush.VapidPublicKey : null;
|
||||
var pushTechnology = vapidPublicKey != null ? PushTechnologyType.WebPush : PushTechnologyType.SignalR;
|
||||
return new()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json;
|
||||
using Azure.Messaging.EventGrid;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Api.Tools.Models.Request;
|
||||
@@ -16,6 +13,7 @@ using Bit.Core.Tools.Models.Data;
|
||||
using Bit.Core.Tools.Repositories;
|
||||
using Bit.Core.Tools.SendFeatures;
|
||||
using Bit.Core.Tools.SendFeatures.Commands.Interfaces;
|
||||
using Bit.Core.Tools.SendFeatures.Queries.Interfaces;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -33,6 +31,9 @@ public class SendsController : Controller
|
||||
private readonly ISendFileStorageService _sendFileStorageService;
|
||||
private readonly IAnonymousSendCommand _anonymousSendCommand;
|
||||
private readonly INonAnonymousSendCommand _nonAnonymousSendCommand;
|
||||
|
||||
private readonly ISendOwnerQuery _sendOwnerQuery;
|
||||
|
||||
private readonly ILogger<SendsController> _logger;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
@@ -42,6 +43,7 @@ public class SendsController : Controller
|
||||
ISendAuthorizationService sendAuthorizationService,
|
||||
IAnonymousSendCommand anonymousSendCommand,
|
||||
INonAnonymousSendCommand nonAnonymousSendCommand,
|
||||
ISendOwnerQuery sendOwnerQuery,
|
||||
ISendFileStorageService sendFileStorageService,
|
||||
ILogger<SendsController> logger,
|
||||
GlobalSettings globalSettings)
|
||||
@@ -51,6 +53,7 @@ public class SendsController : Controller
|
||||
_sendAuthorizationService = sendAuthorizationService;
|
||||
_anonymousSendCommand = anonymousSendCommand;
|
||||
_nonAnonymousSendCommand = nonAnonymousSendCommand;
|
||||
_sendOwnerQuery = sendOwnerQuery;
|
||||
_sendFileStorageService = sendFileStorageService;
|
||||
_logger = logger;
|
||||
_globalSettings = globalSettings;
|
||||
@@ -70,7 +73,11 @@ public class SendsController : Controller
|
||||
|
||||
var guid = new Guid(CoreHelpers.Base64UrlDecode(id));
|
||||
var send = await _sendRepository.GetByIdAsync(guid);
|
||||
SendAccessResult sendAuthResult =
|
||||
if (send == null)
|
||||
{
|
||||
throw new BadRequestException("Could not locate send");
|
||||
}
|
||||
var sendAuthResult =
|
||||
await _sendAuthorizationService.AccessAsync(send, model.Password);
|
||||
if (sendAuthResult.Equals(SendAccessResult.PasswordRequired))
|
||||
{
|
||||
@@ -86,7 +93,7 @@ public class SendsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var sendResponse = new SendAccessResponseModel(send, _globalSettings);
|
||||
var sendResponse = new SendAccessResponseModel(send);
|
||||
if (send.UserId.HasValue && !send.HideEmail.GetValueOrDefault())
|
||||
{
|
||||
var creator = await _userService.GetUserByIdAsync(send.UserId.Value);
|
||||
@@ -181,33 +188,29 @@ public class SendsController : Controller
|
||||
[HttpGet("{id}")]
|
||||
public async Task<SendResponseModel> Get(string id)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var send = await _sendRepository.GetByIdAsync(new Guid(id));
|
||||
if (send == null || send.UserId != userId)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new SendResponseModel(send, _globalSettings);
|
||||
var sendId = new Guid(id);
|
||||
var send = await _sendOwnerQuery.Get(sendId, User);
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
public async Task<ListResponseModel<SendResponseModel>> GetAll()
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var sends = await _sendRepository.GetManyByUserIdAsync(userId);
|
||||
var responses = sends.Select(s => new SendResponseModel(s, _globalSettings));
|
||||
return new ListResponseModel<SendResponseModel>(responses);
|
||||
var sends = await _sendOwnerQuery.GetOwned(User);
|
||||
var responses = sends.Select(s => new SendResponseModel(s));
|
||||
var result = new ListResponseModel<SendResponseModel>(responses);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost("")]
|
||||
public async Task<SendResponseModel> Post([FromBody] SendRequestModel model)
|
||||
{
|
||||
model.ValidateCreation();
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var send = model.ToSend(userId, _sendAuthorizationService);
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(send);
|
||||
return new SendResponseModel(send, _globalSettings);
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
[HttpPost("file/v2")]
|
||||
@@ -229,27 +232,27 @@ public class SendsController : Controller
|
||||
}
|
||||
|
||||
model.ValidateCreation();
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var (send, data) = model.ToSend(userId, model.File.FileName, _sendAuthorizationService);
|
||||
var uploadUrl = await _nonAnonymousSendCommand.SaveFileSendAsync(send, data, model.FileLength.Value);
|
||||
return new SendFileUploadDataResponseModel
|
||||
{
|
||||
Url = uploadUrl,
|
||||
FileUploadType = _sendFileStorageService.FileUploadType,
|
||||
SendResponse = new SendResponseModel(send, _globalSettings)
|
||||
SendResponse = new SendResponseModel(send)
|
||||
};
|
||||
}
|
||||
|
||||
[HttpGet("{id}/file/{fileId}")]
|
||||
public async Task<SendFileUploadDataResponseModel> RenewFileUpload(string id, string fileId)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var sendId = new Guid(id);
|
||||
var send = await _sendRepository.GetByIdAsync(sendId);
|
||||
var fileData = JsonSerializer.Deserialize<SendFileData>(send?.Data);
|
||||
var fileData = JsonSerializer.Deserialize<SendFileData>(send?.Data ?? string.Empty);
|
||||
|
||||
if (send == null || send.Type != SendType.File || (send.UserId.HasValue && send.UserId.Value != userId) ||
|
||||
!send.UserId.HasValue || fileData.Id != fileId || fileData.Validated)
|
||||
!send.UserId.HasValue || fileData?.Id != fileId || fileData.Validated)
|
||||
{
|
||||
// Not found if Send isn't found, user doesn't have access, request is faulty,
|
||||
// or we've already validated the file. This last is to emulate create-only blob permissions for Azure
|
||||
@@ -260,7 +263,7 @@ public class SendsController : Controller
|
||||
{
|
||||
Url = await _sendFileStorageService.GetSendFileUploadUrlAsync(send, fileId),
|
||||
FileUploadType = _sendFileStorageService.FileUploadType,
|
||||
SendResponse = new SendResponseModel(send, _globalSettings),
|
||||
SendResponse = new SendResponseModel(send),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -270,12 +273,16 @@ public class SendsController : Controller
|
||||
[DisableFormValueModelBinding]
|
||||
public async Task PostFileForExistingSend(string id, string fileId)
|
||||
{
|
||||
if (!Request?.ContentType.Contains("multipart/") ?? true)
|
||||
if (!Request?.ContentType?.Contains("multipart/") ?? true)
|
||||
{
|
||||
throw new BadRequestException("Invalid content.");
|
||||
}
|
||||
|
||||
var send = await _sendRepository.GetByIdAsync(new Guid(id));
|
||||
if (send == null)
|
||||
{
|
||||
throw new BadRequestException("Could not locate send");
|
||||
}
|
||||
await Request.GetFileAsync(async (stream) =>
|
||||
{
|
||||
await _nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send);
|
||||
@@ -286,36 +293,39 @@ public class SendsController : Controller
|
||||
public async Task<SendResponseModel> Put(string id, [FromBody] SendRequestModel model)
|
||||
{
|
||||
model.ValidateEdit();
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var send = await _sendRepository.GetByIdAsync(new Guid(id));
|
||||
if (send == null || send.UserId != userId)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(model.ToSend(send, _sendAuthorizationService));
|
||||
return new SendResponseModel(send, _globalSettings);
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(model.UpdateSend(send, _sendAuthorizationService));
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
[HttpPut("{id}/remove-password")]
|
||||
public async Task<SendResponseModel> PutRemovePassword(string id)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var send = await _sendRepository.GetByIdAsync(new Guid(id));
|
||||
if (send == null || send.UserId != userId)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// This endpoint exists because PUT preserves existing Password/Emails when not provided.
|
||||
// This allows clients to update other fields without re-submitting sensitive auth data.
|
||||
send.Password = null;
|
||||
send.AuthType = AuthType.None;
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(send);
|
||||
return new SendResponseModel(send, _globalSettings);
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var userId = _userService.GetProperUserId(User) ?? throw new InvalidOperationException("User ID not found");
|
||||
var send = await _sendRepository.GetByIdAsync(new Guid(id));
|
||||
if (send == null || send.UserId != userId)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Bit.Api.Tools.Utilities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
@@ -10,35 +11,119 @@ using Bit.Core.Tools.Models.Data;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using static System.StringSplitOptions;
|
||||
|
||||
namespace Bit.Api.Tools.Models.Request;
|
||||
|
||||
/// <summary>
|
||||
/// A send request issued by a Bitwarden client
|
||||
/// </summary>
|
||||
public class SendRequestModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the send contains text or file data.
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Estimated length of the file accompanying the send. <see langword="null"/> when
|
||||
/// <see cref="Type"/> is <see cref="SendType.Text"/>.
|
||||
/// </summary>
|
||||
public long? FileLength { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Label for the send.
|
||||
/// </summary>
|
||||
[EncryptedString]
|
||||
[EncryptedStringLength(1000)]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Notes for the send. This is only visible to the owner of the send.
|
||||
/// </summary>
|
||||
[EncryptedString]
|
||||
[EncryptedStringLength(1000)]
|
||||
public string Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A base64-encoded byte array containing the Send's encryption key. This key is
|
||||
/// also provided to send recipients in the Send's URL.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EncryptedString]
|
||||
[EncryptedStringLength(1000)]
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of times a send can be accessed before it expires.
|
||||
/// When this value is <see langword="null" />, there is no limit.
|
||||
/// </summary>
|
||||
[Range(1, int.MaxValue)]
|
||||
public int? MaxAccessCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date after which a send cannot be accessed. When this value is
|
||||
/// <see langword="null"/>, there is no expiration date.
|
||||
/// </summary>
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date after which a send may be automatically deleted from the server.
|
||||
/// When this is <see langword="null" />, the send may be deleted after it has
|
||||
/// exceeded the global send timeout limit.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime? DeletionDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains file metadata uploaded with the send.
|
||||
/// The file content is uploaded separately.
|
||||
/// </summary>
|
||||
public SendFileModel File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains text data uploaded with the send.
|
||||
/// </summary>
|
||||
public SendTextModel Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base64-encoded byte array of a password hash that grants access to the send.
|
||||
/// Mutually exclusive with <see cref="Emails"/>.
|
||||
/// </summary>
|
||||
[StringLength(1000)]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of emails that may access the send using OTP
|
||||
/// authentication. Mutually exclusive with <see cref="Password"/>.
|
||||
/// </summary>
|
||||
[StringLength(4000)]
|
||||
public string Emails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When <see langword="true"/>, send access is disabled.
|
||||
/// Defaults to <see langword="false"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public bool? Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When <see langword="true"/> send access hides the user's email address
|
||||
/// and displays a confirmation message instead. Defaults to <see langword="false"/>.
|
||||
/// </summary>
|
||||
public bool? HideEmail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the request into a send object.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user that owns the send.</param>
|
||||
/// <param name="sendAuthorizationService">Hashes the send password.</param>
|
||||
/// <returns>The send object</returns>
|
||||
public Send ToSend(Guid userId, ISendAuthorizationService sendAuthorizationService)
|
||||
{
|
||||
var send = new Send
|
||||
@@ -46,12 +131,21 @@ public class SendRequestModel
|
||||
Type = Type,
|
||||
UserId = (Guid?)userId
|
||||
};
|
||||
ToSend(send, sendAuthorizationService);
|
||||
send = UpdateSend(send, sendAuthorizationService);
|
||||
return send;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the request into a send object and file data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user that owns the send.</param>
|
||||
/// <param name="fileName">Name of the file uploaded with the send.</param>
|
||||
/// <param name="sendAuthorizationService">Hashes the send password.</param>
|
||||
/// <returns>The send object and file data.</returns>
|
||||
public (Send, SendFileData) ToSend(Guid userId, string fileName, ISendAuthorizationService sendAuthorizationService)
|
||||
{
|
||||
// FIXME: This method does two things: creates a send and a send file data.
|
||||
// It should only do one thing.
|
||||
var send = ToSendBase(new Send
|
||||
{
|
||||
Type = Type,
|
||||
@@ -61,7 +155,13 @@ public class SendRequestModel
|
||||
return (send, data);
|
||||
}
|
||||
|
||||
public Send ToSend(Send existingSend, ISendAuthorizationService sendAuthorizationService)
|
||||
/// <summary>
|
||||
/// Update a send object with request content
|
||||
/// </summary>
|
||||
/// <param name="existingSend">The send to update</param>
|
||||
/// <param name="sendAuthorizationService">Hashes the send password.</param>
|
||||
/// <returns>The send object</returns>
|
||||
public Send UpdateSend(Send existingSend, ISendAuthorizationService sendAuthorizationService)
|
||||
{
|
||||
existingSend = ToSendBase(existingSend, sendAuthorizationService);
|
||||
switch (existingSend.Type)
|
||||
@@ -81,6 +181,12 @@ public class SendRequestModel
|
||||
return existingSend;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the request is internally consistent for send creation.
|
||||
/// </summary>
|
||||
/// <exception cref="BadRequestException">
|
||||
/// Thrown when the send's expiration date has already expired.
|
||||
/// </exception>
|
||||
public void ValidateCreation()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -94,6 +200,13 @@ public class SendRequestModel
|
||||
ValidateEdit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the request is internally consistent for send administration.
|
||||
/// </summary>
|
||||
/// <exception cref="BadRequestException">
|
||||
/// Thrown when the send's deletion date has already expired or when its
|
||||
/// expiration occurs after its deletion.
|
||||
/// </exception>
|
||||
public void ValidateEdit()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -134,12 +247,30 @@ public class SendRequestModel
|
||||
existingSend.ExpirationDate = ExpirationDate;
|
||||
existingSend.DeletionDate = DeletionDate.Value;
|
||||
existingSend.MaxAccessCount = MaxAccessCount;
|
||||
if (!string.IsNullOrWhiteSpace(Password))
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Emails))
|
||||
{
|
||||
// normalize encoding
|
||||
var emails = Emails.Split(',', RemoveEmptyEntries | TrimEntries);
|
||||
existingSend.Emails = string.Join(",", emails);
|
||||
existingSend.Password = null;
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Email;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(Password))
|
||||
{
|
||||
existingSend.Password = authorizationService.HashPassword(Password);
|
||||
existingSend.Emails = null;
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither Password nor Emails provided - preserve existing values and infer AuthType
|
||||
existingSend.AuthType = SendUtilities.InferAuthType(existingSend);
|
||||
}
|
||||
|
||||
existingSend.Disabled = Disabled.GetValueOrDefault();
|
||||
existingSend.HideEmail = HideEmail.GetValueOrDefault();
|
||||
|
||||
return existingSend;
|
||||
}
|
||||
|
||||
@@ -149,8 +280,15 @@ public class SendRequestModel
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A send request issued by a Bitwarden client
|
||||
/// </summary>
|
||||
public class SendWithIdRequestModel : SendRequestModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies the send. When this is <see langword="null" />, the client is requesting
|
||||
/// a new send.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid? Id { get; set; }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Data;
|
||||
@@ -11,9 +10,22 @@ using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Api.Tools.Models.Response;
|
||||
|
||||
/// <summary>
|
||||
/// A response issued to a Bitwarden client in response to access operations.
|
||||
/// </summary>
|
||||
public class SendAccessResponseModel : ResponseModel
|
||||
{
|
||||
public SendAccessResponseModel(Send send, GlobalSettings globalSettings)
|
||||
/// <summary>
|
||||
/// Instantiates a send access response model
|
||||
/// </summary>
|
||||
/// <param name="send">Content to transmit to the client.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="send"/> is <see langword="null" />
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="send" /> has an invalid <see cref="Send.Type"/>.
|
||||
/// </exception>
|
||||
public SendAccessResponseModel(Send send)
|
||||
: base("send-access")
|
||||
{
|
||||
if (send == null)
|
||||
@@ -23,6 +35,7 @@ public class SendAccessResponseModel : ResponseModel
|
||||
|
||||
Id = CoreHelpers.Base64UrlEncode(send.Id.ToByteArray());
|
||||
Type = send.Type;
|
||||
AuthType = send.AuthType;
|
||||
|
||||
SendData sendData;
|
||||
switch (send.Type)
|
||||
@@ -45,11 +58,52 @@ public class SendAccessResponseModel : ResponseModel
|
||||
ExpirationDate = send.ExpirationDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the send in a send URL
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the send contains text or file data.
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Label for the send. This is only visible to the owner of the send.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains a base64-encoded byte array. The array contains
|
||||
/// the E2E-encrypted encrypted content.
|
||||
/// </remarks>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Describes the file attached to the send.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// File content is downloaded separately using
|
||||
/// <see cref="Bit.Api.Tools.Controllers.SendsController.GetSendFileDownloadData" />
|
||||
/// </remarks>
|
||||
public SendFileModel File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains text data uploaded with the send.
|
||||
/// </summary>
|
||||
public SendTextModel Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date after which a send cannot be accessed. When this value is
|
||||
/// <see langword="null"/>, there is no expiration date.
|
||||
/// </summary>
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the person that created the send to the accessor.
|
||||
/// </summary>
|
||||
public string CreatorIdentifier { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Text.Json;
|
||||
using Bit.Api.Tools.Utilities;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Data;
|
||||
@@ -11,9 +11,23 @@ using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Api.Tools.Models.Response;
|
||||
|
||||
/// <summary>
|
||||
/// A response issued to a Bitwarden client in response to ownership operations.
|
||||
/// </summary>
|
||||
/// <seealso cref="SendAccessResponseModel" />
|
||||
public class SendResponseModel : ResponseModel
|
||||
{
|
||||
public SendResponseModel(Send send, GlobalSettings globalSettings)
|
||||
/// <summary>
|
||||
/// Instantiates a send response model
|
||||
/// </summary>
|
||||
/// <param name="send">Content to transmit to the client.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="send"/> is <see langword="null" />
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="send" /> has an invalid <see cref="Send.Type"/>.
|
||||
/// </exception>
|
||||
public SendResponseModel(Send send)
|
||||
: base("send")
|
||||
{
|
||||
if (send == null)
|
||||
@@ -24,6 +38,7 @@ public class SendResponseModel : ResponseModel
|
||||
Id = send.Id;
|
||||
AccessId = CoreHelpers.Base64UrlEncode(send.Id.ToByteArray());
|
||||
Type = send.Type;
|
||||
AuthType = send.AuthType ?? SendUtilities.InferAuthType(send);
|
||||
Key = send.Key;
|
||||
MaxAccessCount = send.MaxAccessCount;
|
||||
AccessCount = send.AccessCount;
|
||||
@@ -31,6 +46,7 @@ public class SendResponseModel : ResponseModel
|
||||
ExpirationDate = send.ExpirationDate;
|
||||
DeletionDate = send.DeletionDate;
|
||||
Password = send.Password;
|
||||
Emails = send.Emails;
|
||||
Disabled = send.Disabled;
|
||||
HideEmail = send.HideEmail.GetValueOrDefault();
|
||||
|
||||
@@ -55,20 +71,113 @@ public class SendResponseModel : ResponseModel
|
||||
Notes = sendData.Notes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the send to its owner
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the send in a send URL
|
||||
/// </summary>
|
||||
public string AccessId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the send contains text or file data.
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Label for the send.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains a base64-encoded byte array. The array contains
|
||||
/// the E2E-encrypted encrypted content.
|
||||
/// </remarks>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Notes for the send. This is only visible to the owner of the send.
|
||||
/// This field is encrypted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains a base64-encoded byte array. The array contains
|
||||
/// the E2E-encrypted encrypted content.
|
||||
/// </remarks>
|
||||
public string Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains file metadata uploaded with the send.
|
||||
/// The file content is uploaded separately.
|
||||
/// </summary>
|
||||
public SendFileModel File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains text data uploaded with the send.
|
||||
/// </summary>
|
||||
public SendTextModel Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A base64-encoded byte array containing the Send's encryption key.
|
||||
/// It's also provided to send recipients in the Send's URL.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains a base64-encoded byte array. The array contains
|
||||
/// the E2E-encrypted content.
|
||||
/// </remarks>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of times a send can be accessed before it expires.
|
||||
/// When this value is <see langword="null" />, there is no limit.
|
||||
/// </summary>
|
||||
public int? MaxAccessCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of times a send has been accessed since it was created.
|
||||
/// </summary>
|
||||
public int AccessCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base64-encoded byte array of a password hash that grants access to the send.
|
||||
/// Mutually exclusive with <see cref="Emails"/>.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of emails that may access the send using OTP
|
||||
/// authentication. Mutually exclusive with <see cref="Password"/>.
|
||||
/// </summary>
|
||||
public string Emails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When <see langword="true"/>, send access is disabled.
|
||||
/// </summary>
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last time this send's data changed.
|
||||
/// </summary>
|
||||
public DateTime RevisionDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date after which a send cannot be accessed. When this value is
|
||||
/// <see langword="null"/>, there is no expiration date.
|
||||
/// </summary>
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date after which a send may be automatically deleted from the server.
|
||||
/// </summary>
|
||||
public DateTime DeletionDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When <see langword="true"/> send access hides the user's email address
|
||||
/// and displays a confirmation message instead.
|
||||
/// </summary>
|
||||
public bool HideEmail { get; set; }
|
||||
}
|
||||
|
||||
23
src/Api/Tools/Utilities/InferAuthType.cs
Normal file
23
src/Api/Tools/Utilities/InferAuthType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Bit.Api.Tools.Utilities;
|
||||
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
|
||||
public class SendUtilities
|
||||
{
|
||||
public static AuthType InferAuthType(Send send)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(send.Password))
|
||||
{
|
||||
return AuthType.Password;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(send.Emails))
|
||||
{
|
||||
return AuthType.Email;
|
||||
}
|
||||
|
||||
return AuthType.None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class SyncResponseModel() : ResponseModel("sync")
|
||||
c => new CollectionDetailsResponseModel(c)) ?? new List<CollectionDetailsResponseModel>();
|
||||
Domains = excludeDomains ? null : new DomainsResponseModel(user, false);
|
||||
Policies = policies?.Select(p => new PolicyResponseModel(p)) ?? new List<PolicyResponseModel>();
|
||||
Sends = sends.Select(s => new SendResponseModel(s, globalSettings));
|
||||
Sends = sends.Select(s => new SendResponseModel(s));
|
||||
UserDecryption = new UserDecryptionResponseModel
|
||||
{
|
||||
MasterPasswordUnlock = user.HasMasterPassword()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record DatadogIntegration(string ApiKey, Uri Uri);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegration(string Token);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegrationConfiguration(string ChannelId);
|
||||
@@ -99,8 +99,8 @@ public class CloudOrganizationSignUpCommand(
|
||||
ReferenceData = signup.Owner.ReferenceData,
|
||||
Enabled = true,
|
||||
LicenseKey = CoreHelpers.SecureRandomString(20),
|
||||
PublicKey = signup.PublicKey,
|
||||
PrivateKey = signup.PrivateKey,
|
||||
PublicKey = signup.Keys?.PublicKey,
|
||||
PrivateKey = signup.Keys?.WrappedPrivateKey,
|
||||
CreationDate = DateTime.UtcNow,
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
Status = OrganizationStatusType.Created,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
public static class OrganizationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the organization public and private keys if provided and not already set.
|
||||
/// This is legacy code for old organizations that were not created with a public/private keypair.
|
||||
/// It is a soft migration that will silently migrate organizations when they perform certain actions,
|
||||
/// e.g. change their details or upgrade their plan.
|
||||
/// </summary>
|
||||
public static void BackfillPublicPrivateKeys(this Organization organization, PublicKeyEncryptionKeyPairData? keyPair)
|
||||
{
|
||||
// Only backfill if both new keys are provided and both old keys are missing.
|
||||
if (string.IsNullOrWhiteSpace(keyPair?.PublicKey) ||
|
||||
string.IsNullOrWhiteSpace(keyPair.WrappedPrivateKey) ||
|
||||
!string.IsNullOrWhiteSpace(organization.PublicKey) ||
|
||||
!string.IsNullOrWhiteSpace(organization.PrivateKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
organization.PublicKey = keyPair.PublicKey;
|
||||
organization.PrivateKey = keyPair.WrappedPrivateKey;
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,8 @@ public class ProviderClientOrganizationSignUpCommand : IProviderClientOrganizati
|
||||
ReferenceData = signup.Owner.ReferenceData,
|
||||
Enabled = true,
|
||||
LicenseKey = CoreHelpers.SecureRandomString(20),
|
||||
PublicKey = signup.PublicKey,
|
||||
PrivateKey = signup.PrivateKey,
|
||||
PublicKey = signup.Keys?.PublicKey,
|
||||
PrivateKey = signup.Keys?.WrappedPrivateKey,
|
||||
CreationDate = DateTime.UtcNow,
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
Status = OrganizationStatusType.Created,
|
||||
|
||||
@@ -39,8 +39,20 @@ public class OrganizationUpdateCommand(
|
||||
var originalBillingEmail = organization.BillingEmail;
|
||||
|
||||
// Apply updates to organization
|
||||
organization.UpdateDetails(request);
|
||||
organization.BackfillPublicPrivateKeys(request);
|
||||
// These values may or may not be sent by the client depending on the operation being performed.
|
||||
// Skip any values not provided.
|
||||
if (request.Name is not null)
|
||||
{
|
||||
organization.Name = request.Name;
|
||||
}
|
||||
|
||||
if (request.BillingEmail is not null)
|
||||
{
|
||||
organization.BillingEmail = request.BillingEmail.ToLowerInvariant().Trim();
|
||||
}
|
||||
|
||||
organization.BackfillPublicPrivateKeys(request.Keys);
|
||||
|
||||
await organizationService.ReplaceAndUpdateCacheAsync(organization, EventType.Organization_Updated);
|
||||
|
||||
// Update billing information in Stripe if required
|
||||
@@ -56,7 +68,7 @@ public class OrganizationUpdateCommand(
|
||||
/// </summary>
|
||||
private async Task<Organization> UpdateSelfHostedAsync(Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
organization.BackfillPublicPrivateKeys(request);
|
||||
organization.BackfillPublicPrivateKeys(request.Keys);
|
||||
await organizationService.ReplaceAndUpdateCacheAsync(organization, EventType.Organization_Updated);
|
||||
return organization;
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
|
||||
public static class OrganizationUpdateExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the organization name and/or billing email.
|
||||
/// Any null property on the request object will be skipped.
|
||||
/// </summary>
|
||||
public static void UpdateDetails(this Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
// These values may or may not be sent by the client depending on the operation being performed.
|
||||
// Skip any values not provided.
|
||||
if (request.Name is not null)
|
||||
{
|
||||
organization.Name = request.Name;
|
||||
}
|
||||
|
||||
if (request.BillingEmail is not null)
|
||||
{
|
||||
organization.BillingEmail = request.BillingEmail.ToLowerInvariant().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the organization public and private keys if provided and not already set.
|
||||
/// This is legacy code for old organizations that were not created with a public/private keypair. It is a soft
|
||||
/// migration that will silently migrate organizations when they change their details.
|
||||
/// </summary>
|
||||
public static void BackfillPublicPrivateKeys(this Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(request.PublicKey) && string.IsNullOrWhiteSpace(organization.PublicKey))
|
||||
{
|
||||
organization.PublicKey = request.PublicKey;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.EncryptedPrivateKey) && string.IsNullOrWhiteSpace(organization.PrivateKey))
|
||||
{
|
||||
organization.PrivateKey = request.EncryptedPrivateKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for updating the name, billing email, and/or public-private keys for an organization (legacy migration code).
|
||||
@@ -22,12 +24,7 @@ public record OrganizationUpdateRequest
|
||||
public string? BillingEmail { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The organization's public key to set (optional, only set if not already present on the organization).
|
||||
/// The organization's public/private key pair to set (optional, only set if not already present on the organization).
|
||||
/// </summary>
|
||||
public string? PublicKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The organization's encrypted private key to set (optional, only set if not already present on the organization).
|
||||
/// </summary>
|
||||
public string? EncryptedPrivateKey { get; init; }
|
||||
public PublicKeyEncryptionKeyPairData? Keys { get; init; }
|
||||
}
|
||||
|
||||
@@ -72,6 +72,17 @@ public class OrganizationDataOwnershipPolicyRequirement : IPolicyRequirement
|
||||
{
|
||||
return _policyDetails.Any(p => p.OrganizationId == organizationId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore storage limits if the organization has data ownership policy enabled.
|
||||
/// Allows users to seamlessly migrate their data into the organization without being blocked by storage limits.
|
||||
/// Organization admins will need to manage storage after migration should overages occur.
|
||||
/// </summary>
|
||||
public bool IgnoreStorageLimitsOnMigration(Guid organizationId)
|
||||
{
|
||||
return _policyDetails.Any(p => p.OrganizationId == organizationId &&
|
||||
p.OrganizationUserStatus == OrganizationUserStatusType.Confirmed);
|
||||
}
|
||||
}
|
||||
|
||||
public record DefaultCollectionRequest(Guid OrganizationUserId, bool ShouldCreateDefaultCollection)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public interface IIntegrationConfigurationDetailsCache
|
||||
{
|
||||
List<OrganizationIntegrationConfigurationDetails> GetConfigurationDetails(
|
||||
Guid organizationId,
|
||||
IntegrationType integrationType,
|
||||
EventType eventType);
|
||||
}
|
||||
@@ -5,12 +5,94 @@ public static class Policies
|
||||
/// <summary>
|
||||
/// Policy for managing access to the Send feature.
|
||||
/// </summary>
|
||||
public const string Send = "Send"; // [Authorize(Policy = Policies.Send)]
|
||||
public const string Application = "Application"; // [Authorize(Policy = Policies.Application)]
|
||||
public const string Web = "Web"; // [Authorize(Policy = Policies.Web)]
|
||||
public const string Push = "Push"; // [Authorize(Policy = Policies.Push)]
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Send)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Send = "Send";
|
||||
|
||||
/// <summary>
|
||||
/// Policy to manage access to general API endpoints.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Application)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Application = "Application";
|
||||
|
||||
/// <summary>
|
||||
/// Policy to manage access to API endpoints intended for use by the Web Vault and browser extension only.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Web)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Web = "Web";
|
||||
|
||||
/// <summary>
|
||||
/// Policy to restrict access to API endpoints for the Push feature.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Push)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Push = "Push";
|
||||
|
||||
// TODO: This is unused
|
||||
public const string Licensing = "Licensing"; // [Authorize(Policy = Policies.Licensing)]
|
||||
public const string Organization = "Organization"; // [Authorize(Policy = Policies.Organization)]
|
||||
public const string Installation = "Installation"; // [Authorize(Policy = Policies.Installation)]
|
||||
public const string Secrets = "Secrets"; // [Authorize(Policy = Policies.Secrets)]
|
||||
|
||||
/// <summary>
|
||||
/// Policy to restrict access to API endpoints related to the Organization features.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Licensing)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Organization = "Organization";
|
||||
|
||||
/// <summary>
|
||||
/// Policy to restrict access to API endpoints related to the setting up new installations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Installation)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Installation = "Installation";
|
||||
|
||||
/// <summary>
|
||||
/// Policy to restrict access to API endpoints for Secrets Manager features.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// Can be used with the <c>Authorize</c> attribute, for example:
|
||||
/// <code>
|
||||
/// [Authorize(Policy = Policies.Secrets)]
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public const string Secrets = "Secrets";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Billing.Caches.Implementations;
|
||||
using Bit.Core.Billing.Licenses;
|
||||
using Bit.Core.Billing.Licenses.Extensions;
|
||||
using Bit.Core.Billing.Organizations.Commands;
|
||||
using Bit.Core.Billing.Organizations.Queries;
|
||||
@@ -28,6 +29,7 @@ public static class ServiceCollectionExtensions
|
||||
services.AddTransient<ISetupIntentCache, SetupIntentDistributedCache>();
|
||||
services.AddTransient<ISubscriberService, SubscriberService>();
|
||||
services.AddLicenseServices();
|
||||
services.AddLicenseOperations();
|
||||
services.AddPricingClient();
|
||||
services.AddPaymentOperations();
|
||||
services.AddOrganizationLicenseCommandsQueries();
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.Billing.Licenses.Extensions;
|
||||
using Bit.Core.Billing.Models.Business;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Core.Billing.Licenses.Models.Api.Response;
|
||||
|
||||
/// <summary>
|
||||
/// Response model containing user license information.
|
||||
/// Separated from subscription data to maintain separation of concerns.
|
||||
/// </summary>
|
||||
public class LicenseResponseModel : ResponseModel
|
||||
{
|
||||
public LicenseResponseModel(UserLicense license, ClaimsPrincipal? claimsPrincipal)
|
||||
: base("license")
|
||||
{
|
||||
License = license;
|
||||
|
||||
// CRITICAL: When a license has a Token (JWT), ALWAYS use the expiration from the token claim
|
||||
// The token's expiration is cryptographically secured and cannot be tampered with
|
||||
// The file's Expires property can be manually edited and should NOT be trusted for display
|
||||
if (claimsPrincipal != null)
|
||||
{
|
||||
Expiration = claimsPrincipal.GetValue<DateTime?>(UserLicenseConstants.Expires);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No token - use the license file expiration (for older licenses without tokens)
|
||||
Expiration = license.Expires;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user's license containing feature entitlements and metadata.
|
||||
/// </summary>
|
||||
public UserLicense License { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The license expiration date.
|
||||
/// Extracted from the cryptographically secured JWT token when available,
|
||||
/// otherwise falls back to the license file's expiration date.
|
||||
/// </summary>
|
||||
public DateTime? Expiration { get; set; }
|
||||
}
|
||||
23
src/Core/Billing/Licenses/Queries/GetUserLicenseQuery.cs
Normal file
23
src/Core/Billing/Licenses/Queries/GetUserLicenseQuery.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Bit.Core.Billing.Licenses.Models.Api.Response;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.Billing.Licenses.Queries;
|
||||
|
||||
public interface IGetUserLicenseQuery
|
||||
{
|
||||
Task<LicenseResponseModel> Run(User user);
|
||||
}
|
||||
|
||||
public class GetUserLicenseQuery(
|
||||
IUserService userService,
|
||||
ILicensingService licensingService) : IGetUserLicenseQuery
|
||||
{
|
||||
public async Task<LicenseResponseModel> Run(User user)
|
||||
{
|
||||
var license = await userService.GenerateLicenseAsync(user);
|
||||
var claimsPrincipal = licensingService.GetClaimsPrincipalFromLicense(license);
|
||||
return new LicenseResponseModel(license, claimsPrincipal);
|
||||
}
|
||||
}
|
||||
13
src/Core/Billing/Licenses/Registrations.cs
Normal file
13
src/Core/Billing/Licenses/Registrations.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Bit.Core.Billing.Licenses.Queries;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Core.Billing.Licenses;
|
||||
|
||||
public static class Registrations
|
||||
{
|
||||
public static void AddLicenseOperations(this IServiceCollection services)
|
||||
{
|
||||
// Queries
|
||||
services.AddTransient<IGetUserLicenseQuery, GetUserLicenseQuery>();
|
||||
}
|
||||
}
|
||||
@@ -228,11 +228,16 @@ public static class FeatureFlagKeys
|
||||
public const string CxpExportMobile = "cxp-export-mobile";
|
||||
|
||||
/* Platform Team */
|
||||
public const string WebPush = "web-push";
|
||||
public const string IpcChannelFramework = "ipc-channel-framework";
|
||||
public const string PushNotificationsWhenLocked = "pm-19388-push-notifications-when-locked";
|
||||
public const string PushNotificationsWhenInactive = "pm-25130-receive-push-notifications-for-inactive-users";
|
||||
|
||||
/* Tools Team */
|
||||
/// <summary>
|
||||
/// Enable this flag to share the send view used by the web and browser clients
|
||||
/// on the desktop client.
|
||||
/// </summary>
|
||||
public const string DesktopSendUIRefresh = "desktop-send-ui-refresh";
|
||||
public const string UseSdkPasswordGenerators = "pm-19976-use-sdk-password-generators";
|
||||
public const string UseChromiumImporter = "pm-23982-chromium-importer";
|
||||
@@ -240,11 +245,20 @@ public static class FeatureFlagKeys
|
||||
public const string SendUIRefresh = "pm-28175-send-ui-refresh";
|
||||
public const string SendEmailOTP = "pm-19051-send-email-verification";
|
||||
|
||||
/// <summary>
|
||||
/// Enable this flag to output email/OTP authenticated sends from the `GET sends` endpoint. When
|
||||
/// this flag is disabled, the `GET sends` endpoint omits email/OTP authenticated sends.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This flag is server-side only, and only inhibits the endpoint returning all sends.
|
||||
/// Email/OTP sends can still be created and downloaded through other endpoints.
|
||||
/// </remarks>
|
||||
public const string PM19051_ListEmailOtpSends = "tools-send-email-otp-listing";
|
||||
|
||||
/* Vault Team */
|
||||
public const string CipherKeyEncryption = "cipher-key-encryption";
|
||||
public const string PM19941MigrateCipherDomainToSdk = "pm-19941-migrate-cipher-domain-to-sdk";
|
||||
public const string PhishingDetection = "phishing-detection";
|
||||
public const string RemoveCardItemTypePolicy = "pm-16442-remove-card-item-type-policy";
|
||||
public const string PM22134SdkCipherListView = "pm-22134-sdk-cipher-list-view";
|
||||
public const string PM22136_SdkCipherEncryption = "pm-22136-sdk-cipher-encryption";
|
||||
public const string PM23904_RiskInsightsForPremium = "pm-23904-risk-insights-for-premium";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Entities;
|
||||
namespace Bit.Core.Dirt.Entities;
|
||||
|
||||
public class OrganizationIntegration : ITableObject<Guid>
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Entities;
|
||||
namespace Bit.Core.Dirt.Entities;
|
||||
|
||||
public class OrganizationIntegrationConfiguration : ITableObject<Guid>
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.Enums;
|
||||
namespace Bit.Core.Dirt.Enums;
|
||||
|
||||
public enum IntegrationType : int
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
namespace Bit.Core.Dirt.Enums;
|
||||
|
||||
public enum OrganizationIntegrationStatus : int
|
||||
{
|
||||
@@ -1,13 +1,15 @@
|
||||
using Azure.Messaging.ServiceBus;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.AdminConsole.Models.Teams;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.AdminConsole.Services.NoopImplementations;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Dirt.Models.Data.Teams;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Dirt.Services.Implementations;
|
||||
using Bit.Core.Dirt.Services.NoopImplementations;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
@@ -1,13 +1,13 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for creating organization integration configurations with validation and cache invalidation support.
|
||||
@@ -1,11 +1,11 @@
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for deleting organization integration configurations with cache invalidation support.
|
||||
@@ -1,9 +1,9 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// Query implementation for retrieving organization integration configurations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for creating organization integration configurations.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for deleting organization integration configurations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Query interface for retrieving organization integration configurations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for updating organization integration configurations.
|
||||
@@ -1,13 +1,13 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Dirt.Services;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for updating organization integration configurations with validation and cache invalidation support.
|
||||
@@ -1,12 +1,12 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for creating organization integrations with cache invalidation support.
|
||||
@@ -1,11 +1,11 @@
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for deleting organization integrations with cache invalidation support.
|
||||
@@ -1,8 +1,8 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Query implementation for retrieving organization integrations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for creating an OrganizationIntegration.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for deleting organization integrations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Query interface for retrieving organization integrations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Command interface for updating organization integrations.
|
||||
@@ -1,12 +1,12 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations;
|
||||
namespace Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Command implementation for updating organization integrations with cache invalidation support.
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record DatadogIntegration(string ApiKey, Uri Uri);
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record DatadogIntegrationConfigurationDetails(string ApiKey, Uri Uri);
|
||||
@@ -1,7 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class DatadogListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record HecIntegration(Uri Uri, string Scheme, string Token, string? Service = null);
|
||||
@@ -1,7 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class HecListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IEventListenerConfiguration
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IIntegrationListenerConfiguration : IEventListenerConfiguration
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public interface IIntegrationMessage
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Categories of event integration failures used for classification and retry logic.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationFilterGroup
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public enum IntegrationFilterOperation
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationFilterRule
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of an integration handler operation, including success status,
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationMessage : IIntegrationMessage
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationOAuthState
|
||||
{
|
||||
@@ -4,7 +4,7 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class IntegrationTemplateContext(EventMessage eventMessage)
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public abstract class ListenerConfiguration
|
||||
{
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.Models.Data.Organizations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class OrganizationIntegrationConfigurationDetails
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class RepositoryListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IEventListenerConfiguration
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegration(string Token);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegrationConfiguration(string ChannelId);
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record SlackIntegrationConfigurationDetails(string ChannelId, string Token);
|
||||
@@ -1,7 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class SlackListenerConfiguration(GlobalSettings globalSettings) :
|
||||
ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.Core.Models.Teams;
|
||||
using Bit.Core.Dirt.Models.Data.Teams;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record TeamsIntegration(
|
||||
string TenantId,
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record TeamsIntegrationConfigurationDetails(string ChannelId, Uri ServiceUrl);
|
||||
@@ -1,7 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class TeamsListenerConfiguration(GlobalSettings globalSettings) :
|
||||
ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegration(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegrationConfiguration(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public record WebhookIntegrationConfigurationDetails(Uri Uri, string? Scheme = null, string? Token = null);
|
||||
@@ -1,7 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
namespace Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
|
||||
public class WebhookListenerConfiguration(GlobalSettings globalSettings)
|
||||
: ListenerConfiguration(globalSettings), IIntegrationListenerConfiguration
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Models.Slack;
|
||||
namespace Bit.Core.Dirt.Models.Data.Slack;
|
||||
|
||||
public abstract class SlackApiResponse
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Models.Teams;
|
||||
namespace Bit.Core.Dirt.Models.Data.Teams;
|
||||
|
||||
/// <summary>Represents the response returned by the Microsoft OAuth 2.0 token endpoint.
|
||||
/// See <see href="https://learn.microsoft.com/graph/auth-v2-user">Microsoft identity platform and OAuth 2.0
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Bot.Connector.Authentication;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Teams;
|
||||
namespace Bit.Core.Dirt.Models.Data.Teams;
|
||||
|
||||
public class TeamsBotCredentialProvider(string clientId, string clientSecret) : ICredentialProvider
|
||||
{
|
||||
@@ -1,8 +1,10 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Enums;
|
||||
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.Repositories;
|
||||
namespace Bit.Core.Dirt.Repositories;
|
||||
|
||||
public interface IOrganizationIntegrationConfigurationRepository : IRepository<OrganizationIntegrationConfiguration, Guid>
|
||||
{
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user