mirror of
https://github.com/bitwarden/server
synced 2026-01-11 13:03:27 +00:00
Merge remote-tracking branch 'origin/master' into ac/ac-1638/disallow-secrets-manager-for-msp-managed-organizations
This commit is contained in:
@@ -19,6 +19,7 @@ using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Admin.Controllers;
|
||||
|
||||
@@ -47,6 +48,7 @@ public class OrganizationsController : Controller
|
||||
private readonly ISecretRepository _secretRepository;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||
private readonly IStripeSyncService _stripeSyncService;
|
||||
|
||||
public OrganizationsController(
|
||||
IOrganizationService organizationService,
|
||||
@@ -70,7 +72,8 @@ public class OrganizationsController : Controller
|
||||
ICurrentContext currentContext,
|
||||
ISecretRepository secretRepository,
|
||||
IProjectRepository projectRepository,
|
||||
IServiceAccountRepository serviceAccountRepository)
|
||||
IServiceAccountRepository serviceAccountRepository,
|
||||
IStripeSyncService stripeSyncService)
|
||||
{
|
||||
_organizationService = organizationService;
|
||||
_organizationRepository = organizationRepository;
|
||||
@@ -94,6 +97,7 @@ public class OrganizationsController : Controller
|
||||
_secretRepository = secretRepository;
|
||||
_projectRepository = projectRepository;
|
||||
_serviceAccountRepository = serviceAccountRepository;
|
||||
_stripeSyncService = stripeSyncService;
|
||||
}
|
||||
|
||||
[RequirePermission(Permission.Org_List_View)]
|
||||
@@ -208,6 +212,16 @@ public class OrganizationsController : Controller
|
||||
throw new BadRequestException("Plan does not support Secrets Manager");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _stripeSyncService.UpdateCustomerEmailAddress(organization.GatewayCustomerId, organization.BillingEmail);
|
||||
}
|
||||
catch (StripeException stripeException)
|
||||
{
|
||||
_logger.LogError(stripeException, "Failed to update billing email address in Stripe for Organization with ID '{organizationId}'", organization.Id);
|
||||
throw;
|
||||
}
|
||||
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.OrganizationEditedByAdmin, organization, _currentContext)
|
||||
@@ -215,6 +229,7 @@ public class OrganizationsController : Controller
|
||||
EventRaisedByUser = _userService.GetUserName(User),
|
||||
SalesAssistedTrialStarted = model.SalesAssistedTrialStarted,
|
||||
});
|
||||
|
||||
return RedirectToAction("Edit", new { id });
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,13 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="email" class="form-control" asp-for="BillingEmail" readonly='@(!canEditBilling)'>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
asp-for="BillingEmail"
|
||||
readonly='@(!canEditBilling)'
|
||||
pattern="@(@"[^@\s]+@[^@\s]+\.[^@\s]+")"
|
||||
title="Email address must be in the format 'address@domain.com'.">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -116,6 +116,7 @@ public class OrganizationSubscriptionResponseModel : OrganizationResponseModel
|
||||
{
|
||||
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
||||
UpcomingInvoice = subscription.UpcomingInvoice != null ? new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
||||
Discount = subscription.Discount != null ? new BillingCustomerDiscount(subscription.Discount) : null;
|
||||
Expiration = DateTime.UtcNow.AddYears(1); // Not used, so just give it a value.
|
||||
|
||||
if (hideSensitiveData)
|
||||
@@ -146,6 +147,7 @@ public class OrganizationSubscriptionResponseModel : OrganizationResponseModel
|
||||
|
||||
public string StorageName { get; set; }
|
||||
public double? StorageGb { get; set; }
|
||||
public BillingCustomerDiscount Discount { get; set; }
|
||||
public BillingSubscription Subscription { get; set; }
|
||||
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ public class SubscriptionResponseModel : ResponseModel
|
||||
Subscription = subscription.Subscription != null ? new BillingSubscription(subscription.Subscription) : null;
|
||||
UpcomingInvoice = subscription.UpcomingInvoice != null ?
|
||||
new BillingSubscriptionUpcomingInvoice(subscription.UpcomingInvoice) : null;
|
||||
Discount = subscription.Discount != null ? new BillingCustomerDiscount(subscription.Discount) : null;
|
||||
StorageName = user.Storage.HasValue ? CoreHelpers.ReadableBytesSize(user.Storage.Value) : null;
|
||||
StorageGb = user.Storage.HasValue ? Math.Round(user.Storage.Value / 1073741824D, 2) : 0; // 1 GB
|
||||
MaxStorageGb = user.MaxStorageGb;
|
||||
@@ -41,11 +42,24 @@ public class SubscriptionResponseModel : ResponseModel
|
||||
public short? MaxStorageGb { get; set; }
|
||||
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
||||
public BillingSubscription Subscription { get; set; }
|
||||
public BillingCustomerDiscount Discount { get; set; }
|
||||
public UserLicense License { get; set; }
|
||||
public DateTime? Expiration { get; set; }
|
||||
public bool UsingInAppPurchase { get; set; }
|
||||
}
|
||||
|
||||
public class BillingCustomerDiscount
|
||||
{
|
||||
public BillingCustomerDiscount(SubscriptionInfo.BillingCustomerDiscount discount)
|
||||
{
|
||||
Id = discount.Id;
|
||||
Active = discount.Active;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
|
||||
public class BillingSubscription
|
||||
{
|
||||
public BillingSubscription(SubscriptionInfo.BillingSubscription sub)
|
||||
|
||||
@@ -36,6 +36,7 @@ public class CiphersController : Controller
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly ILogger<CiphersController> _logger;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly Version _cipherKeyEncryptionMinimumVersion = new Version(Constants.CipherKeyEncryptionMinimumVersion);
|
||||
|
||||
public CiphersController(
|
||||
ICipherRepository cipherRepository,
|
||||
@@ -177,6 +178,8 @@ public class CiphersController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
ValidateItemLevelEncryptionIsAvailable(cipher);
|
||||
|
||||
var collectionIds = (await _collectionCipherRepository.GetManyByUserIdCipherIdAsync(userId, id)).Select(c => c.CollectionId).ToList();
|
||||
var modelOrgId = string.IsNullOrWhiteSpace(model.OrganizationId) ?
|
||||
(Guid?)null : new Guid(model.OrganizationId);
|
||||
@@ -198,6 +201,9 @@ public class CiphersController : Controller
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(id);
|
||||
|
||||
ValidateItemLevelEncryptionIsAvailable(cipher);
|
||||
|
||||
if (cipher == null || !cipher.OrganizationId.HasValue ||
|
||||
!await _currentContext.EditAnyCollection(cipher.OrganizationId.Value))
|
||||
{
|
||||
@@ -576,6 +582,8 @@ public class CiphersController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
ValidateItemLevelEncryptionIsAvailable(cipher);
|
||||
|
||||
if (request.FileSize > CipherService.MAX_FILE_SIZE)
|
||||
{
|
||||
throw new BadRequestException($"Max file size is {CipherService.MAX_FILE_SIZE_READABLE}.");
|
||||
@@ -795,4 +803,12 @@ public class CiphersController : Controller
|
||||
throw new BadRequestException("Invalid content.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateItemLevelEncryptionIsAvailable(Cipher cipher)
|
||||
{
|
||||
if (cipher.Key != null && _currentContext.ClientVersion < _cipherKeyEncryptionMinimumVersion)
|
||||
{
|
||||
throw new BadRequestException("Cannot edit item. Update to the latest version of Bitwarden and try again.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public class CipherRequestModel
|
||||
public string FolderId { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public CipherRepromptType Reprompt { get; set; }
|
||||
public string Key { get; set; }
|
||||
[Required]
|
||||
[EncryptedString]
|
||||
[EncryptedStringLength(1000)]
|
||||
@@ -86,6 +87,7 @@ public class CipherRequestModel
|
||||
}
|
||||
|
||||
existingCipher.Reprompt = Reprompt;
|
||||
existingCipher.Key = Key;
|
||||
|
||||
var hasAttachments2 = (Attachments2?.Count ?? 0) > 0;
|
||||
var hasAttachments = (Attachments?.Count ?? 0) > 0;
|
||||
|
||||
@@ -63,6 +63,7 @@ public class CipherMiniResponseModel : ResponseModel
|
||||
CreationDate = cipher.CreationDate;
|
||||
DeletedDate = cipher.DeletedDate;
|
||||
Reprompt = cipher.Reprompt.GetValueOrDefault(CipherRepromptType.None);
|
||||
Key = cipher.Key;
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
@@ -83,6 +84,7 @@ public class CipherMiniResponseModel : ResponseModel
|
||||
public DateTime CreationDate { get; set; }
|
||||
public DateTime? DeletedDate { get; set; }
|
||||
public CipherRepromptType Reprompt { get; set; }
|
||||
public string Key { get; set; }
|
||||
}
|
||||
|
||||
public class CipherResponseModel : CipherMiniResponseModel
|
||||
|
||||
@@ -19,6 +19,8 @@ public static class Constants
|
||||
/// their subscription has expired.
|
||||
/// </summary>
|
||||
public const int OrganizationSelfHostSubscriptionGracePeriodDays = 60;
|
||||
|
||||
public const string CipherKeyEncryptionMinimumVersion = "2023.9.2";
|
||||
}
|
||||
|
||||
public static class TokenPurposes
|
||||
@@ -37,6 +39,7 @@ public static class FeatureFlagKeys
|
||||
public const string DisplayLowKdfIterationWarning = "display-kdf-iteration-warning";
|
||||
public const string TrustedDeviceEncryption = "trusted-device-encryption";
|
||||
public const string AutofillV2 = "autofill-v2";
|
||||
public const string BrowserFilelessImport = "browser-fileless-import";
|
||||
|
||||
public static List<string> GetAllKeys()
|
||||
{
|
||||
|
||||
@@ -5,10 +5,25 @@ namespace Bit.Core.Models.Business;
|
||||
|
||||
public class SubscriptionInfo
|
||||
{
|
||||
public BillingCustomerDiscount Discount { get; set; }
|
||||
public BillingSubscription Subscription { get; set; }
|
||||
public BillingUpcomingInvoice UpcomingInvoice { get; set; }
|
||||
public bool UsingInAppPurchase { get; set; }
|
||||
|
||||
public class BillingCustomerDiscount
|
||||
{
|
||||
public BillingCustomerDiscount() { }
|
||||
|
||||
public BillingCustomerDiscount(Discount discount)
|
||||
{
|
||||
Id = discount.Id;
|
||||
Active = discount.Start != null && discount.End == null;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public bool Active { get; }
|
||||
}
|
||||
|
||||
public class BillingSubscription
|
||||
{
|
||||
public BillingSubscription(Subscription sub)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Settings;
|
||||
using LaunchDarkly.Logging;
|
||||
using LaunchDarkly.Sdk.Server;
|
||||
using LaunchDarkly.Sdk.Server.Integrations;
|
||||
|
||||
@@ -14,6 +15,7 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
IGlobalSettings globalSettings)
|
||||
{
|
||||
var ldConfig = Configuration.Builder(globalSettings.LaunchDarkly?.SdkKey);
|
||||
ldConfig.Logging(Components.Logging().Level(LogLevel.Error));
|
||||
|
||||
if (string.IsNullOrEmpty(globalSettings.LaunchDarkly?.SdkKey))
|
||||
{
|
||||
|
||||
@@ -1557,10 +1557,19 @@ public class StripePaymentService : IPaymentService
|
||||
{
|
||||
var subscriptionInfo = new SubscriptionInfo();
|
||||
|
||||
if (subscriber.IsUser() && !string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
|
||||
if (!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
|
||||
{
|
||||
var customer = await _stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId);
|
||||
subscriptionInfo.UsingInAppPurchase = customer.Metadata.ContainsKey("appleReceipt");
|
||||
|
||||
if (customer.Discount != null)
|
||||
{
|
||||
subscriptionInfo.Discount = new SubscriptionInfo.BillingCustomerDiscount(customer.Discount);
|
||||
}
|
||||
|
||||
if (subscriber.IsUser())
|
||||
{
|
||||
subscriptionInfo.UsingInAppPurchase = customer.Metadata.ContainsKey("appleReceipt");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
|
||||
|
||||
@@ -21,6 +21,7 @@ public class Cipher : ITableObject<Guid>, ICloneable
|
||||
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
||||
public DateTime? DeletedDate { get; set; }
|
||||
public Enums.CipherRepromptType? Reprompt { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
||||
public void SetNewId()
|
||||
{
|
||||
|
||||
@@ -392,7 +392,8 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
SET
|
||||
[Data] = TC.[Data],
|
||||
[Attachments] = TC.[Attachments],
|
||||
[RevisionDate] = TC.[RevisionDate]
|
||||
[RevisionDate] = TC.[RevisionDate],
|
||||
[Key] = TC.[Key]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
INNER JOIN
|
||||
@@ -506,7 +507,8 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
[Data] = TC.[Data],
|
||||
[Attachments] = TC.[Attachments],
|
||||
[RevisionDate] = TC.[RevisionDate],
|
||||
[DeletedDate] = TC.[DeletedDate]
|
||||
[DeletedDate] = TC.[DeletedDate],
|
||||
[Key] = TC.[Key]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
INNER JOIN
|
||||
@@ -728,6 +730,8 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
ciphersTable.Columns.Add(deletedDateColumn);
|
||||
var repromptColumn = new DataColumn(nameof(c.Reprompt), typeof(short));
|
||||
ciphersTable.Columns.Add(repromptColumn);
|
||||
var keyColummn = new DataColumn(nameof(c.Key), typeof(string));
|
||||
ciphersTable.Columns.Add(keyColummn);
|
||||
|
||||
foreach (DataColumn col in ciphersTable.Columns)
|
||||
{
|
||||
@@ -754,6 +758,7 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
row[revisionDateColumn] = cipher.RevisionDate;
|
||||
row[deletedDateColumn] = cipher.DeletedDate.HasValue ? (object)cipher.DeletedDate : DBNull.Value;
|
||||
row[repromptColumn] = cipher.Reprompt;
|
||||
row[keyColummn] = cipher.Key;
|
||||
|
||||
ciphersTable.Rows.Add(row);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ public class UserCipherDetailsQuery : IQuery<CipherDetails>
|
||||
Reprompt = c.Reprompt,
|
||||
ViewPassword = true,
|
||||
OrganizationUseTotp = false,
|
||||
Key = c.Key
|
||||
});
|
||||
return union;
|
||||
}
|
||||
|
||||
@@ -366,6 +366,7 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
Reprompt = c.Reprompt,
|
||||
ViewPassword = true,
|
||||
OrganizationUseTotp = false,
|
||||
Key = c.Key
|
||||
};
|
||||
}
|
||||
var ciphers = await cipherDetailsView.ToListAsync();
|
||||
@@ -591,6 +592,7 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
trackedCipher.Attachments = cipher.Attachments;
|
||||
trackedCipher.RevisionDate = cipher.RevisionDate;
|
||||
trackedCipher.DeletedDate = cipher.DeletedDate;
|
||||
trackedCipher.Key = cipher.Key;
|
||||
|
||||
await transaction.CommitAsync();
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ public class CipherDetailsQuery : IQuery<CipherDetails>
|
||||
RevisionDate = c.RevisionDate,
|
||||
DeletedDate = c.DeletedDate,
|
||||
Reprompt = c.Reprompt,
|
||||
Key = c.Key,
|
||||
Favorite = _userId.HasValue && c.Favorites != null && c.Favorites.ToLowerInvariant().Contains($"\"{_userId}\":true"),
|
||||
FolderId = (_ignoreFolders || !_userId.HasValue || c.Folders == null || !c.Folders.ToLowerInvariant().Contains(_userId.Value.ToString())) ?
|
||||
null :
|
||||
|
||||
@@ -26,6 +26,7 @@ SELECT
|
||||
ELSE TRY_CONVERT(UNIQUEIDENTIFIER, JSON_VALUE(C.[Folders], CONCAT('$."', @UserId, '"')))
|
||||
END [FolderId],
|
||||
C.[DeletedDate],
|
||||
C.[Reprompt]
|
||||
C.[Reprompt],
|
||||
C.[Key]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
@@ -15,7 +15,8 @@
|
||||
@ViewPassword BIT, -- not used
|
||||
@OrganizationUseTotp BIT, -- not used
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
@@ -35,7 +36,8 @@ BEGIN
|
||||
[CreationDate],
|
||||
[RevisionDate],
|
||||
[DeletedDate],
|
||||
[Reprompt]
|
||||
[Reprompt],
|
||||
[Key]
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@@ -49,7 +51,8 @@ BEGIN
|
||||
@CreationDate,
|
||||
@RevisionDate,
|
||||
@DeletedDate,
|
||||
@Reprompt
|
||||
@Reprompt,
|
||||
@Key
|
||||
)
|
||||
|
||||
IF @OrganizationId IS NOT NULL
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@OrganizationUseTotp BIT, -- not used
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL,
|
||||
@CollectionIds AS [dbo].[GuidIdArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
@@ -23,7 +24,7 @@ BEGIN
|
||||
|
||||
EXEC [dbo].[CipherDetails_Create] @Id, @UserId, @OrganizationId, @Type, @Data, @Favorites, @Folders,
|
||||
@Attachments, @CreationDate, @RevisionDate, @FolderId, @Favorite, @Edit, @ViewPassword,
|
||||
@OrganizationUseTotp, @DeletedDate, @Reprompt
|
||||
@OrganizationUseTotp, @DeletedDate, @Reprompt, @Key
|
||||
|
||||
DECLARE @UpdateCollectionsSuccess INT
|
||||
EXEC @UpdateCollectionsSuccess = [dbo].[Cipher_UpdateCollections] @Id, @UserId, @OrganizationId, @CollectionIds
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
@Data NVARCHAR(MAX),
|
||||
@Favorites NVARCHAR(MAX), -- not used
|
||||
@Folders NVARCHAR(MAX), -- not used
|
||||
@Attachments NVARCHAR(MAX), -- not used
|
||||
@Attachments NVARCHAR(MAX),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7),
|
||||
@FolderId UNIQUEIDENTIFIER,
|
||||
@@ -15,7 +15,8 @@
|
||||
@ViewPassword BIT, -- not used
|
||||
@OrganizationUseTotp BIT, -- not used
|
||||
@DeletedDate DATETIME2(2),
|
||||
@Reprompt TINYINT
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
@@ -48,10 +49,12 @@ BEGIN
|
||||
ELSE
|
||||
JSON_MODIFY([Favorites], @UserIdPath, NULL)
|
||||
END,
|
||||
[Attachments] = @Attachments,
|
||||
[Reprompt] = @Reprompt,
|
||||
[CreationDate] = @CreationDate,
|
||||
[RevisionDate] = @RevisionDate,
|
||||
[DeletedDate] = @DeletedDate
|
||||
[DeletedDate] = @DeletedDate,
|
||||
[Key] = @Key
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7),
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
@@ -28,7 +29,8 @@ BEGIN
|
||||
[CreationDate],
|
||||
[RevisionDate],
|
||||
[DeletedDate],
|
||||
[Reprompt]
|
||||
[Reprompt],
|
||||
[Key]
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@@ -43,7 +45,8 @@ BEGIN
|
||||
@CreationDate,
|
||||
@RevisionDate,
|
||||
@DeletedDate,
|
||||
@Reprompt
|
||||
@Reprompt,
|
||||
@Key
|
||||
)
|
||||
|
||||
IF @OrganizationId IS NOT NULL
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
@RevisionDate DATETIME2(7),
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL,
|
||||
@CollectionIds AS [dbo].[GuidIdArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
EXEC [dbo].[Cipher_Create] @Id, @UserId, @OrganizationId, @Type, @Data, @Favorites, @Folders,
|
||||
@Attachments, @CreationDate, @RevisionDate, @DeletedDate, @Reprompt
|
||||
@Attachments, @CreationDate, @RevisionDate, @DeletedDate, @Reprompt, @Key
|
||||
|
||||
DECLARE @UpdateCollectionsSuccess INT
|
||||
EXEC @UpdateCollectionsSuccess = [dbo].[Cipher_UpdateCollections] @Id, @UserId, @OrganizationId, @CollectionIds
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7),
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
@@ -28,7 +29,8 @@ BEGIN
|
||||
[CreationDate] = @CreationDate,
|
||||
[RevisionDate] = @RevisionDate,
|
||||
[DeletedDate] = @DeletedDate,
|
||||
[Reprompt] = @Reprompt
|
||||
[Reprompt] = @Reprompt,
|
||||
[Key] = @Key
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
@RevisionDate DATETIME2(7),
|
||||
@DeletedDate DATETIME2(7),
|
||||
@Reprompt TINYINT,
|
||||
@Key VARCHAR(MAX) = NULL,
|
||||
@CollectionIds AS [dbo].[GuidIdArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
@@ -36,7 +37,8 @@ BEGIN
|
||||
[Data] = @Data,
|
||||
[Attachments] = @Attachments,
|
||||
[RevisionDate] = @RevisionDate,
|
||||
[DeletedDate] = @DeletedDate
|
||||
[DeletedDate] = @DeletedDate,
|
||||
[Key] = @Key
|
||||
-- No need to update CreationDate, Favorites, Folders, or Type since that data will not change
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
|
||||
@@ -12,6 +12,7 @@ CREATE TABLE [dbo].[Cipher] (
|
||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||
[DeletedDate] DATETIME2 (7) NULL,
|
||||
[Reprompt] TINYINT NULL,
|
||||
[Key] VARCHAR(MAX) NULL,
|
||||
CONSTRAINT [PK_Cipher] PRIMARY KEY CLUSTERED ([Id] ASC),
|
||||
CONSTRAINT [FK_Cipher_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
|
||||
CONSTRAINT [FK_Cipher_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
|
||||
|
||||
Reference in New Issue
Block a user