1
0
mirror of https://github.com/bitwarden/server synced 2025-12-22 03:03:33 +00:00

create ArchiveCipher table

This commit is contained in:
jaasen-livefront
2025-11-13 18:30:30 -08:00
parent 30ff175f8e
commit 89a0eb2068
7 changed files with 169 additions and 0 deletions

View File

@@ -25,6 +25,12 @@ public class Cipher : ITableObject<Guid>, ICloneable
public DateTime? DeletedDate { get; set; } public DateTime? DeletedDate { get; set; }
public Enums.CipherRepromptType? Reprompt { get; set; } public Enums.CipherRepromptType? Reprompt { get; set; }
public string Key { get; set; } public string Key { get; set; }
/// <summary>
/// Deprecated as of Nov 2025.
/// Source of truth is now CipherArchive (CipherId + UserId).
/// Kept for backward compatibility during phased migration.
/// </summary>
public DateTime? ArchivedDate { get; set; } public DateTime? ArchivedDate { get; set; }
public void SetNewId() public void SetNewId()

View File

@@ -0,0 +1,12 @@
#nullable disable
namespace Bit.Core.Vault.Entities;
public class CipherArchive
{
public Guid CipherId { get; set; }
public Guid UserId { get; set; }
public DateTime ArchivedDate { get; set; }
public Cipher Cipher { get; set; }
}

View File

@@ -41,6 +41,7 @@ public class DatabaseContext : DbContext
public DbSet<ApiKey> ApiKeys { get; set; } public DbSet<ApiKey> ApiKeys { get; set; }
public DbSet<Cache> Cache { get; set; } public DbSet<Cache> Cache { get; set; }
public DbSet<Cipher> Ciphers { get; set; } public DbSet<Cipher> Ciphers { get; set; }
public DbSet<CipherArchive> CipherArchives { get; set; }
public DbSet<Collection> Collections { get; set; } public DbSet<Collection> Collections { get; set; }
public DbSet<CollectionCipher> CollectionCiphers { get; set; } public DbSet<CollectionCipher> CollectionCiphers { get; set; }
public DbSet<CollectionGroup> CollectionGroups { get; set; } public DbSet<CollectionGroup> CollectionGroups { get; set; }
@@ -162,6 +163,7 @@ public class DatabaseContext : DbContext
} }
eCipher.ToTable(nameof(Cipher)); eCipher.ToTable(nameof(Cipher));
eCipherArchive.ToTable(nameof(CipherArchive));
eCollection.ToTable(nameof(Collection)); eCollection.ToTable(nameof(Collection));
eCollectionCipher.ToTable(nameof(CollectionCipher)); eCollectionCipher.ToTable(nameof(CollectionCipher));
eEmergencyAccess.ToTable(nameof(EmergencyAccess)); eEmergencyAccess.ToTable(nameof(EmergencyAccess));

View File

@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bit.Infrastructure.EntityFramework.Vault.Configurations;
public class CipherArchiveConfiguration : IEntityTypeConfiguration<CipherArchive>
{
public void Configure(EntityTypeBuilder<CipherArchive> builder)
{
builder.ToTable(nameof(CipherArchive));
builder.HasKey(ca => new { ca.CipherId, ca.UserId });
builder
.HasOne(ca => ca.Cipher)
.WithMany()
.HasForeignKey(ca => ca.CipherId)
.OnDelete(DeleteBehavior.Cascade);
// If you want explicit mapping:
builder.Property(ca => ca.ArchivedDate).IsRequired();
}
}

View File

@@ -0,0 +1,13 @@
#nullable disable
using Bit.Infrastructure.EntityFramework.Vault.Models;
public class CipherArchive
{
public Guid CipherId { get; set; }
public Guid UserId { get; set; }
public DateTime ArchivedDate { get; set; }
// Optional navigation props you can drop these if you don't want them.
public Cipher Cipher { get; set; }
}

View File

@@ -0,0 +1,55 @@
IF OBJECT_ID(N'[dbo].[CipherArchive]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[CipherArchive]
(
[CipherId] UNIQUEIDENTIFIER NOT NULL,
[UserId] UNIQUEIDENTIFIER NOT NULL,
[ArchivedDate] DATETIME2(7) NOT NULL,
CONSTRAINT [PK_CipherArchive]
PRIMARY KEY CLUSTERED ([CipherId], [UserId])
);
END;
GO
IF NOT EXISTS (
SELECT 1
FROM sys.foreign_keys
WHERE name = N'FK_CipherArchive_Cipher'
AND parent_object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
ALTER TABLE [dbo].[CipherArchive]
ADD CONSTRAINT [FK_CipherArchive_Cipher]
FOREIGN KEY ([CipherId])
REFERENCES [dbo].[Cipher]([Id])
ON DELETE CASCADE;
END;
GO
IF NOT EXISTS (
SELECT 1
FROM sys.foreign_keys
WHERE name = N'FK_CipherArchive_User'
AND parent_object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
ALTER TABLE [dbo].[CipherArchive]
ADD CONSTRAINT [FK_CipherArchive_User]
FOREIGN KEY ([UserId])
REFERENCES [dbo].[User]([Id])
ON DELETE CASCADE;
END;
GO
IF NOT EXISTS (
SELECT 1
FROM sys.indexes
WHERE name = N'IX_CipherArchive_UserId'
AND object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_CipherArchive_UserId]
ON [dbo].[CipherArchive]([UserId]);
END;
GO

View File

@@ -0,0 +1,58 @@
IF OBJECT_ID(N'[dbo].[CipherArchive]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[CipherArchive]
(
[CipherId] UNIQUEIDENTIFIER NOT NULL,
[UserId] UNIQUEIDENTIFIER NOT NULL,
[ArchivedDate] DATETIME2(7) NOT NULL,
CONSTRAINT [PK_CipherArchive]
PRIMARY KEY CLUSTERED ([CipherId], [UserId])
);
END;
GO
-- FK → Cipher
IF NOT EXISTS (
SELECT 1
FROM sys.foreign_keys
WHERE name = N'FK_CipherArchive_Cipher'
AND parent_object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
ALTER TABLE [dbo].[CipherArchive]
ADD CONSTRAINT [FK_CipherArchive_Cipher]
FOREIGN KEY ([CipherId])
REFERENCES [dbo].[Cipher]([Id])
ON DELETE CASCADE;
END;
GO
-- FK → User
IF NOT EXISTS (
SELECT 1
FROM sys.foreign_keys
WHERE name = N'FK_CipherArchive_User'
AND parent_object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
ALTER TABLE [dbo].[CipherArchive]
ADD CONSTRAINT [FK_CipherArchive_User]
FOREIGN KEY ([UserId])
REFERENCES [dbo].[User]([Id])
ON DELETE CASCADE;
END;
GO
-- Optional index for queries by user
IF NOT EXISTS (
SELECT 1
FROM sys.indexes
WHERE name = N'IX_CipherArchive_UserId'
AND object_id = OBJECT_ID(N'[dbo].[CipherArchive]', N'U')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_CipherArchive_UserId]
ON [dbo].[CipherArchive]([UserId]);
END;
GO