Public Access
The server now forgets a deletion past its retention and refuses cursors from before it. The client then reads everything again, but everything again says nothing about what went. So a machine away for longer than the retention kept those items for good, and its next edit of one put it back on the server for everyone. A read from the beginning now marks each item it reads, keeping the mark in the sync state because the read can span passes. When it finishes, it removes the items of the synced types it never marked. Two kinds are kept: items newer than the read's bound, which this machine pushed during it, and items with a change still waiting, which are the user's work. For those, the push finds the server without the item and sends it as a create, as before, but now records a RecreatedAfterCollection conflict and counts it, so the sync message says so instead of undoing someone's deletion silently. The bound is the highest sequence the cache held when the read began, or anything higher it has read since. Taking only what the read returned would have left the last item of a vault in place for ever.
479 lines
18 KiB
C#
479 lines
18 KiB
C#
// <auto-generated />
|
|
using System;
|
|
using DodoSSH.Client.Storage;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
|
|
#nullable disable
|
|
|
|
namespace DodoSSH.Client.Storage.Migrations
|
|
{
|
|
[DbContext(typeof(ClientCacheContext))]
|
|
partial class ClientCacheContextModelSnapshot : ModelSnapshot
|
|
{
|
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
|
{
|
|
#pragma warning disable 612, 618
|
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.10");
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.CachedItemRow", b =>
|
|
{
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.Property<int>("EntityType")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("entity_type");
|
|
|
|
b.Property<Guid>("EntityId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("entity_id");
|
|
|
|
b.Property<byte>("AadVersion")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("aad_version");
|
|
|
|
b.Property<long>("ChangeSequence")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("change_sequence");
|
|
|
|
b.Property<Guid?>("DataKeyId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("data_key_id");
|
|
|
|
b.Property<bool>("IsDeleted")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("is_deleted");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<byte[]>("Payload")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("payload");
|
|
|
|
b.Property<byte[]>("ProtectedFields")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("protected_fields");
|
|
|
|
b.Property<long?>("SweepMark")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("sweep_mark");
|
|
|
|
b.Property<long>("UpdatedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("updated_at_utc");
|
|
|
|
b.Property<int>("Version")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("version");
|
|
|
|
b.Property<byte[]>("WrappedDataKey")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("wrapped_data_key");
|
|
|
|
b.HasKey("VaultId", "EntityType", "EntityId")
|
|
.HasName("pk_item");
|
|
|
|
b.HasIndex("VaultId", "ChangeSequence")
|
|
.HasDatabaseName("ix_item_vault_id_change_sequence");
|
|
|
|
b.HasIndex("VaultId", "EntityType")
|
|
.HasDatabaseName("ix_item_vault_id_entity_type");
|
|
|
|
b.ToTable("item", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.CachedVaultKeyWrapRow", b =>
|
|
{
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<byte[]>("WrappedKey")
|
|
.IsRequired()
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("wrapped_key");
|
|
|
|
b.HasKey("VaultId", "KeyGeneration")
|
|
.HasName("pk_vault_key_wrap");
|
|
|
|
b.ToTable("vault_key_wrap", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.CachedVaultRow", b =>
|
|
{
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.Property<bool>("Hidden")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("hidden");
|
|
|
|
b.Property<bool>("IsPersonal")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("is_personal");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<string>("Name")
|
|
.IsRequired()
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("name");
|
|
|
|
b.Property<int>("Permissions")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("permissions");
|
|
|
|
b.Property<bool>("RekeyRequired")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("rekey_required");
|
|
|
|
b.Property<Guid?>("TeamId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("team_id");
|
|
|
|
b.Property<long>("UpdatedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("updated_at_utc");
|
|
|
|
b.Property<byte[]>("WrappedVaultKey")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("wrapped_vault_key");
|
|
|
|
b.HasKey("VaultId")
|
|
.HasName("pk_vault");
|
|
|
|
b.ToTable("vault", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.ConflictRow", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("id");
|
|
|
|
b.Property<bool>("Acknowledged")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("acknowledged");
|
|
|
|
b.Property<byte[]>("Detail")
|
|
.IsRequired()
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("detail");
|
|
|
|
b.Property<long>("DetectedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("detected_at_utc");
|
|
|
|
b.Property<Guid>("EntityId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("entity_id");
|
|
|
|
b.Property<int>("EntityType")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("entity_type");
|
|
|
|
b.Property<int>("Kind")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("kind");
|
|
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.HasKey("Id")
|
|
.HasName("pk_conflict");
|
|
|
|
b.HasIndex("VaultId", "Acknowledged")
|
|
.HasDatabaseName("ix_conflict_vault_id_acknowledged");
|
|
|
|
b.HasIndex("VaultId", "EntityType", "EntityId")
|
|
.HasDatabaseName("ix_conflict_vault_id_entity_type_entity_id");
|
|
|
|
b.ToTable("conflict", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.OutboxRow", b =>
|
|
{
|
|
b.Property<long>("Sequence")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("sequence");
|
|
|
|
b.Property<byte>("AadVersion")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("aad_version");
|
|
|
|
b.Property<byte?>("AncestorAadVersion")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("ancestor_aad_version");
|
|
|
|
b.Property<Guid?>("AncestorDataKeyId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("ancestor_data_key_id");
|
|
|
|
b.Property<uint?>("AncestorKeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("ancestor_key_generation");
|
|
|
|
b.Property<byte[]>("AncestorPayload")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("ancestor_payload");
|
|
|
|
b.Property<byte[]>("AncestorProtectedFields")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("ancestor_protected_fields");
|
|
|
|
b.Property<int?>("AncestorVersion")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("ancestor_version");
|
|
|
|
b.Property<byte[]>("AncestorWrappedDataKey")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("ancestor_wrapped_data_key");
|
|
|
|
b.Property<int>("Attempts")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("attempts");
|
|
|
|
b.Property<Guid?>("DataKeyId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("data_key_id");
|
|
|
|
b.Property<Guid>("EntityId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("entity_id");
|
|
|
|
b.Property<int>("EntityType")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("entity_type");
|
|
|
|
b.Property<int?>("ExpectedVersion")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("expected_version");
|
|
|
|
b.Property<bool>("IsParked")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("is_parked");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<string>("LastError")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("last_error");
|
|
|
|
b.Property<int>("Operation")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("operation");
|
|
|
|
b.Property<Guid>("OperationId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("operation_id");
|
|
|
|
b.Property<byte[]>("Payload")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("payload");
|
|
|
|
b.Property<byte[]>("ProtectedFields")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("protected_fields");
|
|
|
|
b.Property<long>("QueuedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("queued_at_utc");
|
|
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.Property<byte[]>("WrappedDataKey")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("wrapped_data_key");
|
|
|
|
b.HasKey("Sequence")
|
|
.HasName("pk_outbox");
|
|
|
|
b.HasIndex("OperationId")
|
|
.IsUnique()
|
|
.HasDatabaseName("ix_outbox_operation_id");
|
|
|
|
b.HasIndex("VaultId", "EntityType", "EntityId")
|
|
.IsUnique()
|
|
.HasDatabaseName("ix_outbox_vault_id_entity_type_entity_id");
|
|
|
|
b.HasIndex("VaultId", "IsParked", "Sequence")
|
|
.HasDatabaseName("ix_outbox_vault_id_is_parked_sequence");
|
|
|
|
b.ToTable("outbox", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.RememberedSignInRow", b =>
|
|
{
|
|
b.Property<int>("Id")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("id");
|
|
|
|
b.Property<byte[]>("SealedRefreshToken")
|
|
.IsRequired()
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("sealed_refresh_token");
|
|
|
|
b.Property<long>("UpdatedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("updated_at_utc");
|
|
|
|
b.HasKey("Id")
|
|
.HasName("pk_remembered_sign_in");
|
|
|
|
b.ToTable("remembered_sign_in", null, t =>
|
|
{
|
|
t.HasCheckConstraint("ck_remembered_sign_in_singleton", "id = 1");
|
|
});
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.SyncStateRow", b =>
|
|
{
|
|
b.Property<Guid>("VaultId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("vault_id");
|
|
|
|
b.Property<string>("Cursor")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("cursor");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<long?>("LastPulledAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("last_pulled_at_utc");
|
|
|
|
b.Property<long?>("LastPushedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("last_pushed_at_utc");
|
|
|
|
b.Property<string>("PulledTypes")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("pulled_types");
|
|
|
|
b.Property<long>("ServerTimeSkewMs")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("server_time_skew_ms");
|
|
|
|
b.Property<long?>("SweepMark")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("sweep_mark");
|
|
|
|
b.Property<long>("SweepSeenUpTo")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("sweep_seen_up_to");
|
|
|
|
b.HasKey("VaultId")
|
|
.HasName("pk_sync_state");
|
|
|
|
b.ToTable("sync_state", (string)null);
|
|
});
|
|
|
|
modelBuilder.Entity("DodoSSH.Client.Storage.UnlockMaterialRow", b =>
|
|
{
|
|
b.Property<int>("Id")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("id");
|
|
|
|
b.Property<Guid?>("DeviceId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("device_id");
|
|
|
|
b.Property<byte[]>("DeviceWrappedPrivateKey")
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("device_wrapped_private_key");
|
|
|
|
b.Property<string>("DisplayName")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("display_name");
|
|
|
|
b.Property<string>("Email")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("email");
|
|
|
|
b.Property<string>("Issuer")
|
|
.IsRequired()
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("issuer");
|
|
|
|
b.Property<string>("KdfAlgorithm")
|
|
.IsRequired()
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("kdf_algorithm");
|
|
|
|
b.Property<int>("KdfMemoryKibibytes")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("kdf_memory_kibibytes");
|
|
|
|
b.Property<int>("KdfParallelism")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("kdf_parallelism");
|
|
|
|
b.Property<int>("KdfPasses")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("kdf_passes");
|
|
|
|
b.Property<byte[]>("KdfSalt")
|
|
.IsRequired()
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("kdf_salt");
|
|
|
|
b.Property<uint>("KeyGeneration")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("key_generation");
|
|
|
|
b.Property<string>("ServerUrl")
|
|
.IsRequired()
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("server_url");
|
|
|
|
b.Property<string>("Subject")
|
|
.IsRequired()
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("subject");
|
|
|
|
b.Property<long>("UpdatedAtUtc")
|
|
.HasColumnType("INTEGER")
|
|
.HasColumnName("updated_at_utc");
|
|
|
|
b.Property<Guid>("UserId")
|
|
.HasColumnType("TEXT")
|
|
.HasColumnName("user_id");
|
|
|
|
b.Property<byte[]>("WrappedPrivateKey")
|
|
.IsRequired()
|
|
.HasColumnType("BLOB")
|
|
.HasColumnName("wrapped_private_key");
|
|
|
|
b.HasKey("Id")
|
|
.HasName("pk_unlock_material");
|
|
|
|
b.ToTable("unlock_material", null, t =>
|
|
{
|
|
t.HasCheckConstraint("ck_unlock_material_singleton", "id = 1");
|
|
});
|
|
});
|
|
#pragma warning restore 612, 618
|
|
}
|
|
}
|
|
}
|