Public Access
Add data model, DbContext and initial migration (M1)
Schema for identity, vaults, grants, hosts and the sync change log, verified against a real PostgreSQL 18 container rather than an in-memory provider: partial unique indexes, CHECK constraints, citext and identity-always columns are all provider behaviour that an in-memory fake would not exercise. Invariants pushed into the database, so they hold even when application code has a bug: - ck_host_relay_target is a security boundary, not tidiness. A host may carry a plaintext hostname and port ONLY when relay is deliberately enabled. Both directions are tested; the important one is that relay-disabled hosts cannot carry an address, since otherwise a bug would silently give the server infrastructure visibility it was never granted. - ck_vault_owner: exactly one of owner_user_id or team_id, or permission resolution would have no defined answer. - ck_vault_key_grant_recipient: member grants name a user; recovery and escrow grants are wrapped to a key and must not. - ck_user_key_wrap_kdf: a password-derived wrap without its parameters is permanently unopenable, so a partial write is rejected outright. Present from the first migration on purpose: - GrantKind (Member/Recovery/Escrow). Recovery cannot be bolted on later — every vault created before it existed would be unrecoverable by design. - team and team_membership, though team features are M3. Adding them later would mean introducing a foreign key on a live vault table. - Host.ContentKeyId, reserved for per-item content keys wrapped to individual users. - user_key as its own table, so key rotation does not require altering the user row. Two things verified rather than assumed: - Npgsql's UseXminAsConcurrencyToken helper no longer exists in EF 10, so xmin is mapped directly in XminConcurrency. The generated migration *looks* like it creates an xmin column; it does not. Confirmed by inspecting pg_attribute (attnum -2, a system column) and by grepping the emitted DDL. A test pins both, because had it created a real column PostgreSQL would have rejected the name. - EF Core is now pinned centrally. The Npgsql provider asks for 10.0.4 while EntityFrameworkCore.Design pulls 10.0.10, and because Design is PrivateAssets=all that higher version does not flow to referencing projects — producing a CS1705 in any test project referencing Infrastructure. Also commits artifacts/schema/v0.1.sql, the idempotent script, as the baseline for future upgrade tests. Verified: 0 warnings, 122 tests pass (27 new against Postgres), format clean.
This commit is contained in:
+971
@@ -0,0 +1,971 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using DodoSSH.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DodoSSH.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(DodoDbContext))]
|
||||
[Migration("20260728113419_InitialSchema")]
|
||||
partial class InitialSchema
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("dodo")
|
||||
.HasAnnotation("ProductVersion", "10.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "citext");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Device", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("EnrolledAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("enrolled_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastSeenAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_seen_at_utc");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("Platform")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("platform");
|
||||
|
||||
b.Property<byte[]>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("public_key");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_device");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_device_user_id");
|
||||
|
||||
b.ToTable("device", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Host", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<long>("ChangeSequence")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("change_sequence");
|
||||
|
||||
b.Property<Guid?>("ContentKeyId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("content_key_id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid>("CreatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("created_by_user_id");
|
||||
|
||||
b.Property<byte[]>("DataKeyWrap")
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("data_key_wrap");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<Guid?>("GroupId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("group_id");
|
||||
|
||||
b.Property<string>("Hostname")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)")
|
||||
.HasColumnName("hostname");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<byte[]>("Payload")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("payload");
|
||||
|
||||
b.Property<short>("PayloadAadVersion")
|
||||
.HasColumnType("smallint")
|
||||
.HasColumnName("payload_aad_version");
|
||||
|
||||
b.Property<int?>("Port")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("port");
|
||||
|
||||
b.Property<bool>("RelayEnabled")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("relay_enabled");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<Guid>("UpdatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("updated_by_user_id");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.Property<int>("Version")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("version");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_host");
|
||||
|
||||
b.HasIndex("VaultId")
|
||||
.HasDatabaseName("ix_host_vault_live")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.HasIndex("VaultId", "ChangeSequence")
|
||||
.HasDatabaseName("ix_host_vault_id_change_sequence");
|
||||
|
||||
b.ToTable("host", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_host_port_range", "port IS NULL OR (port BETWEEN 1 AND 65535)");
|
||||
|
||||
t.HasCheckConstraint("ck_host_relay_target", "(relay_enabled AND hostname IS NOT NULL AND port IS NOT NULL)\nOR (NOT relay_enabled AND hostname IS NULL AND port IS NULL)");
|
||||
|
||||
t.HasCheckConstraint("ck_host_version", "version >= 1");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.KeyLogEntry", b =>
|
||||
{
|
||||
b.Property<long>("Sequence")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("sequence");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property<long>("Sequence"));
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("EncryptionPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("encryption_public_key");
|
||||
|
||||
b.Property<int>("Generation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("generation");
|
||||
|
||||
b.Property<byte[]>("Hash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("hash");
|
||||
|
||||
b.Property<byte[]>("PreviousHash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("previous_hash");
|
||||
|
||||
b.Property<byte[]>("SigningPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signing_public_key");
|
||||
|
||||
b.Property<byte[]>("StatementSignature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("statement_signature");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Sequence")
|
||||
.HasName("pk_key_log");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_key_log_hash");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_key_log_user_id");
|
||||
|
||||
b.ToTable("key_log", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.SyncChange", b =>
|
||||
{
|
||||
b.Property<long>("Sequence")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("sequence");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property<long>("Sequence"));
|
||||
|
||||
b.Property<Guid>("ActorUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("actor_user_id");
|
||||
|
||||
b.Property<Guid>("EntityId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("entity_id");
|
||||
|
||||
b.Property<int>("EntityType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("entity_type");
|
||||
|
||||
b.Property<DateTimeOffset>("OccurredAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("occurred_at_utc");
|
||||
|
||||
b.Property<int>("Operation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("operation");
|
||||
|
||||
b.Property<int>("Revision")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("revision");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.HasKey("Sequence")
|
||||
.HasName("pk_sync_change");
|
||||
|
||||
b.HasIndex("VaultId", "Sequence")
|
||||
.HasDatabaseName("ix_sync_change_vault_id_sequence");
|
||||
|
||||
b.HasIndex("VaultId", "EntityId", "Sequence")
|
||||
.IsDescending(false, false, true)
|
||||
.HasDatabaseName("ix_sync_change_vault_id_entity_id_sequence");
|
||||
|
||||
b.ToTable("sync_change", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.SyncOperationReceipt", b =>
|
||||
{
|
||||
b.Property<Guid>("OperationId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("operation_id");
|
||||
|
||||
b.Property<long?>("AppliedChangeSequence")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("applied_change_sequence");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<int?>("ResultVersion")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("result_version");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.HasKey("OperationId")
|
||||
.HasName("pk_sync_operation_receipt");
|
||||
|
||||
b.HasIndex("VaultId", "CreatedAtUtc")
|
||||
.HasDatabaseName("ix_sync_operation_receipt_vault_id_created_at_utc");
|
||||
|
||||
b.ToTable("sync_operation_receipt", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Team", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid>("CreatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("created_by_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("citext")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_team");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_team_slug")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.ToTable("team", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.TeamMembership", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<Guid?>("InvitedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("invited_by_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("JoinedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("joined_at_utc");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("role");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<Guid>("TeamId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("team_id");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_team_membership");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_team_membership_user_id");
|
||||
|
||||
b.HasIndex("TeamId", "UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_team_membership_team_id_user_id")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.ToTable("team_membership", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("display_name");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(320)
|
||||
.HasColumnType("citext")
|
||||
.HasColumnName("email");
|
||||
|
||||
b.Property<DateTimeOffset?>("EnrolledAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("enrolled_at_utc");
|
||||
|
||||
b.Property<string>("Issuer")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasColumnName("issuer");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastSeenAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_seen_at_utc");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("subject");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_account");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_account_email")
|
||||
.HasFilter("email IS NOT NULL AND deleted_at_utc IS NULL");
|
||||
|
||||
b.HasIndex("Issuer", "Subject")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_account_issuer_subject");
|
||||
|
||||
b.ToTable("user_account", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("EncryptionPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("encryption_public_key");
|
||||
|
||||
b.Property<byte[]>("FingerprintSha256")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("fingerprint_sha256");
|
||||
|
||||
b.Property<int>("Generation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("generation");
|
||||
|
||||
b.Property<string>("IdentityProviderBinding")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("identity_provider_binding");
|
||||
|
||||
b.Property<bool>("IsCurrent")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_current");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<byte[]>("SigningPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signing_public_key");
|
||||
|
||||
b.Property<string>("Statement")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("statement");
|
||||
|
||||
b.Property<byte[]>("StatementSignature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("statement_signature");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_key");
|
||||
|
||||
b.HasIndex("FingerprintSha256")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_fingerprint_sha256");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_current")
|
||||
.HasFilter("is_current");
|
||||
|
||||
b.HasIndex("UserId", "Generation")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_user_id_generation");
|
||||
|
||||
b.ToTable("user_key", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKeyWrap", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid?>("DeviceId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("device_id");
|
||||
|
||||
b.Property<string>("KdfAlgorithm")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)")
|
||||
.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")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("kdf_salt");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("kind");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastUsedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_used_at_utc");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<byte[]>("Wrap")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("wrap");
|
||||
|
||||
b.Property<int>("WrapVersion")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("wrap_version");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_key_wrap");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.HasDatabaseName("ix_user_key_wrap_device_id");
|
||||
|
||||
b.HasIndex("UserId", "DeviceId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_wrap_user_device")
|
||||
.HasFilter("device_id IS NOT NULL");
|
||||
|
||||
b.HasIndex("UserId", "Kind")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_wrap_user_kind")
|
||||
.HasFilter("device_id IS NULL");
|
||||
|
||||
b.ToTable("user_key_wrap", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_user_key_wrap_device", "(kind = 2 AND device_id IS NOT NULL) OR (kind <> 2 AND device_id IS NULL)");
|
||||
|
||||
t.HasCheckConstraint("ck_user_key_wrap_kdf", "(kind IN (1, 3) AND kdf_algorithm IS NOT NULL AND kdf_salt IS NOT NULL\n AND kdf_memory_kibibytes IS NOT NULL AND kdf_passes IS NOT NULL\n AND kdf_parallelism IS NOT NULL)\nOR (kind IN (2, 4) AND kdf_algorithm IS NULL AND kdf_salt IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("OwnerKind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("owner_kind");
|
||||
|
||||
b.Property<Guid?>("OwnerUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("owner_user_id");
|
||||
|
||||
b.Property<int>("RekeyReason")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("rekey_reason");
|
||||
|
||||
b.Property<bool>("RekeyRequired")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("rekey_required");
|
||||
|
||||
b.Property<Guid?>("TeamId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("team_id");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_vault");
|
||||
|
||||
b.HasIndex("OwnerUserId")
|
||||
.HasDatabaseName("ix_vault_owner_user_id");
|
||||
|
||||
b.HasIndex("TeamId")
|
||||
.HasDatabaseName("ix_vault_team_id");
|
||||
|
||||
b.ToTable("vault", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_vault_key_generation", "key_generation >= 1");
|
||||
|
||||
t.HasCheckConstraint("ck_vault_owner", "(owner_kind = 1 AND owner_user_id IS NOT NULL AND team_id IS NULL)\nOR (owner_kind = 2 AND team_id IS NOT NULL AND owner_user_id IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.VaultKeyGrant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("GranterKeyFingerprint")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("granter_key_fingerprint");
|
||||
|
||||
b.Property<Guid>("GranterUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("granter_user_id");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<byte[]>("KeyLogHead")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("key_log_head");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("kind");
|
||||
|
||||
b.Property<byte[]>("RecipientKeyFingerprint")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("recipient_key_fingerprint");
|
||||
|
||||
b.Property<Guid?>("RecipientUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("recipient_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<byte[]>("Signature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signature");
|
||||
|
||||
b.Property<int>("State")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("state");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.Property<byte[]>("WrappedKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("wrapped_key");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_vault_key_grant");
|
||||
|
||||
b.HasIndex("RecipientUserId")
|
||||
.HasDatabaseName("ix_vault_key_grant_recipient_user_id");
|
||||
|
||||
b.HasIndex("VaultId", "KeyGeneration", "RecipientUserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_vault_key_grant_vault_id_key_generation_recipient_user_id")
|
||||
.HasFilter("revoked_at_utc IS NULL AND recipient_user_id IS NOT NULL");
|
||||
|
||||
b.ToTable("vault_key_grant", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_vault_key_grant_recipient", "(kind = 1 AND recipient_user_id IS NOT NULL) OR (kind <> 1 AND recipient_user_id IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("Devices")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_device_users_user_id");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Host", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Vault", "Vault")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("VaultId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_host_vaults_vault_id");
|
||||
|
||||
b.Navigation("Vault");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.TeamMembership", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Team", "Team")
|
||||
.WithMany("Memberships")
|
||||
.HasForeignKey("TeamId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_team_membership_team_team_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_team_membership_users_user_id");
|
||||
|
||||
b.Navigation("Team");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKey", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("Keys")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_user_key_user_account_user_id");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKeyWrap", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_user_key_wrap_device_device_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("KeyWraps")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_user_key_wrap_user_account_user_id");
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "OwnerUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerUserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.HasConstraintName("fk_vault_user_account_owner_user_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.Team", "Team")
|
||||
.WithMany()
|
||||
.HasForeignKey("TeamId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.HasConstraintName("fk_vault_team_team_id");
|
||||
|
||||
b.Navigation("OwnerUser");
|
||||
|
||||
b.Navigation("Team");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.VaultKeyGrant", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "RecipientUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_vault_key_grant_user_account_recipient_user_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.Vault", "Vault")
|
||||
.WithMany("KeyGrants")
|
||||
.HasForeignKey("VaultId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_vault_key_grant_vault_vault_id");
|
||||
|
||||
b.Navigation("RecipientUser");
|
||||
|
||||
b.Navigation("Vault");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Team", b =>
|
||||
{
|
||||
b.Navigation("Memberships");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserAccount", b =>
|
||||
{
|
||||
b.Navigation("Devices");
|
||||
|
||||
b.Navigation("KeyWraps");
|
||||
|
||||
b.Navigation("Keys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.Navigation("Hosts");
|
||||
|
||||
b.Navigation("KeyGrants");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,583 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DodoSSH.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialSchema : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "dodo");
|
||||
|
||||
migrationBuilder.AlterDatabase()
|
||||
.Annotation("Npgsql:PostgresExtension:citext", ",,");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "key_log",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
sequence = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
generation = table.Column<int>(type: "integer", nullable: false),
|
||||
encryption_public_key = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
signing_public_key = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
statement_signature = table.Column<byte[]>(type: "bytea", maxLength: 64, nullable: false),
|
||||
previous_hash = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
hash = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_key_log", x => x.sequence);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "sync_change",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
sequence = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityAlwaysColumn),
|
||||
vault_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
entity_type = table.Column<int>(type: "integer", nullable: false),
|
||||
entity_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
operation = table.Column<int>(type: "integer", nullable: false),
|
||||
revision = table.Column<int>(type: "integer", nullable: false),
|
||||
actor_user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
occurred_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_sync_change", x => x.sequence);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "sync_operation_receipt",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
operation_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
vault_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
applied_change_sequence = table.Column<long>(type: "bigint", nullable: true),
|
||||
result_version = table.Column<int>(type: "integer", nullable: true),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_sync_operation_receipt", x => x.operation_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "team",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
slug = table.Column<string>(type: "citext", maxLength: 128, nullable: false),
|
||||
description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||
created_by_user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_team", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "user_account",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
issuer = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false),
|
||||
subject = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
email = table.Column<string>(type: "citext", maxLength: 320, nullable: true),
|
||||
display_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
status = table.Column<int>(type: "integer", nullable: false),
|
||||
enrolled_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
updated_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
last_seen_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
deleted_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_user_account", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "device",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
platform = table.Column<int>(type: "integer", nullable: false),
|
||||
public_key = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
enrolled_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
last_seen_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
revoked_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_device", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_device_users_user_id",
|
||||
column: x => x.user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "team_membership",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
team_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
role = table.Column<int>(type: "integer", nullable: false),
|
||||
status = table.Column<int>(type: "integer", nullable: false),
|
||||
invited_by_user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
joined_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_team_membership", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_team_membership_team_team_id",
|
||||
column: x => x.team_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "team",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_team_membership_users_user_id",
|
||||
column: x => x.user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "user_key",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
generation = table.Column<int>(type: "integer", nullable: false),
|
||||
encryption_public_key = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
signing_public_key = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
fingerprint_sha256 = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
statement = table.Column<string>(type: "jsonb", nullable: false),
|
||||
statement_signature = table.Column<byte[]>(type: "bytea", maxLength: 64, nullable: false),
|
||||
identity_provider_binding = table.Column<string>(type: "jsonb", nullable: true),
|
||||
is_current = table.Column<bool>(type: "boolean", nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
revoked_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_user_key", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_user_key_user_account_user_id",
|
||||
column: x => x.user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "vault",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
owner_kind = table.Column<int>(type: "integer", nullable: false),
|
||||
owner_user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
team_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
key_generation = table.Column<int>(type: "integer", nullable: false),
|
||||
rekey_required = table.Column<bool>(type: "boolean", nullable: false),
|
||||
rekey_reason = table.Column<int>(type: "integer", nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
updated_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_vault", x => x.id);
|
||||
table.CheckConstraint("ck_vault_key_generation", "key_generation >= 1");
|
||||
table.CheckConstraint("ck_vault_owner", "(owner_kind = 1 AND owner_user_id IS NOT NULL AND team_id IS NULL)\nOR (owner_kind = 2 AND team_id IS NOT NULL AND owner_user_id IS NULL)");
|
||||
table.ForeignKey(
|
||||
name: "fk_vault_team_team_id",
|
||||
column: x => x.team_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "team",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "fk_vault_user_account_owner_user_id",
|
||||
column: x => x.owner_user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "user_key_wrap",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
kind = table.Column<int>(type: "integer", nullable: false),
|
||||
device_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
wrap = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||
wrap_version = table.Column<int>(type: "integer", nullable: false),
|
||||
kdf_algorithm = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
kdf_salt = table.Column<byte[]>(type: "bytea", maxLength: 64, nullable: true),
|
||||
kdf_memory_kibibytes = table.Column<int>(type: "integer", nullable: true),
|
||||
kdf_passes = table.Column<int>(type: "integer", nullable: true),
|
||||
kdf_parallelism = table.Column<int>(type: "integer", nullable: true),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
last_used_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_user_key_wrap", x => x.id);
|
||||
table.CheckConstraint("ck_user_key_wrap_device", "(kind = 2 AND device_id IS NOT NULL) OR (kind <> 2 AND device_id IS NULL)");
|
||||
table.CheckConstraint("ck_user_key_wrap_kdf", "(kind IN (1, 3) AND kdf_algorithm IS NOT NULL AND kdf_salt IS NOT NULL\n AND kdf_memory_kibibytes IS NOT NULL AND kdf_passes IS NOT NULL\n AND kdf_parallelism IS NOT NULL)\nOR (kind IN (2, 4) AND kdf_algorithm IS NULL AND kdf_salt IS NULL)");
|
||||
table.ForeignKey(
|
||||
name: "fk_user_key_wrap_device_device_id",
|
||||
column: x => x.device_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "device",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_user_key_wrap_user_account_user_id",
|
||||
column: x => x.user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "host",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
vault_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
payload = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||
data_key_wrap = table.Column<byte[]>(type: "bytea", nullable: true),
|
||||
content_key_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
key_generation = table.Column<int>(type: "integer", nullable: false),
|
||||
payload_aad_version = table.Column<short>(type: "smallint", nullable: false),
|
||||
relay_enabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
hostname = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
|
||||
port = table.Column<int>(type: "integer", nullable: true),
|
||||
group_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
version = table.Column<int>(type: "integer", nullable: false),
|
||||
change_sequence = table.Column<long>(type: "bigint", nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
updated_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
created_by_user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
updated_by_user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_host", x => x.id);
|
||||
table.CheckConstraint("ck_host_port_range", "port IS NULL OR (port BETWEEN 1 AND 65535)");
|
||||
table.CheckConstraint("ck_host_relay_target", "(relay_enabled AND hostname IS NOT NULL AND port IS NOT NULL)\nOR (NOT relay_enabled AND hostname IS NULL AND port IS NULL)");
|
||||
table.CheckConstraint("ck_host_version", "version >= 1");
|
||||
table.ForeignKey(
|
||||
name: "fk_host_vaults_vault_id",
|
||||
column: x => x.vault_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "vault",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "vault_key_grant",
|
||||
schema: "dodo",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
vault_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
key_generation = table.Column<int>(type: "integer", nullable: false),
|
||||
kind = table.Column<int>(type: "integer", nullable: false),
|
||||
recipient_user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
recipient_key_fingerprint = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
wrapped_key = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||
granter_user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
granter_key_fingerprint = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: false),
|
||||
key_log_head = table.Column<byte[]>(type: "bytea", maxLength: 32, nullable: true),
|
||||
signature = table.Column<byte[]>(type: "bytea", maxLength: 64, nullable: false),
|
||||
state = table.Column<int>(type: "integer", nullable: false),
|
||||
created_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
revoked_at_utc = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
xmin = table.Column<uint>(type: "xid", rowVersion: true, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_vault_key_grant", x => x.id);
|
||||
table.CheckConstraint("ck_vault_key_grant_recipient", "(kind = 1 AND recipient_user_id IS NOT NULL) OR (kind <> 1 AND recipient_user_id IS NULL)");
|
||||
table.ForeignKey(
|
||||
name: "fk_vault_key_grant_user_account_recipient_user_id",
|
||||
column: x => x.recipient_user_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "user_account",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_vault_key_grant_vault_vault_id",
|
||||
column: x => x.vault_id,
|
||||
principalSchema: "dodo",
|
||||
principalTable: "vault",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_device_user_id",
|
||||
schema: "dodo",
|
||||
table: "device",
|
||||
column: "user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_host_vault_id_change_sequence",
|
||||
schema: "dodo",
|
||||
table: "host",
|
||||
columns: new[] { "vault_id", "change_sequence" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_host_vault_live",
|
||||
schema: "dodo",
|
||||
table: "host",
|
||||
column: "vault_id",
|
||||
filter: "deleted_at_utc IS NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_key_log_hash",
|
||||
schema: "dodo",
|
||||
table: "key_log",
|
||||
column: "hash",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_key_log_user_id",
|
||||
schema: "dodo",
|
||||
table: "key_log",
|
||||
column: "user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_sync_change_vault_id_entity_id_sequence",
|
||||
schema: "dodo",
|
||||
table: "sync_change",
|
||||
columns: new[] { "vault_id", "entity_id", "sequence" },
|
||||
descending: new[] { false, false, true });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_sync_change_vault_id_sequence",
|
||||
schema: "dodo",
|
||||
table: "sync_change",
|
||||
columns: new[] { "vault_id", "sequence" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_sync_operation_receipt_vault_id_created_at_utc",
|
||||
schema: "dodo",
|
||||
table: "sync_operation_receipt",
|
||||
columns: new[] { "vault_id", "created_at_utc" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_team_slug",
|
||||
schema: "dodo",
|
||||
table: "team",
|
||||
column: "slug",
|
||||
unique: true,
|
||||
filter: "deleted_at_utc IS NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_team_membership_team_id_user_id",
|
||||
schema: "dodo",
|
||||
table: "team_membership",
|
||||
columns: new[] { "team_id", "user_id" },
|
||||
unique: true,
|
||||
filter: "deleted_at_utc IS NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_team_membership_user_id",
|
||||
schema: "dodo",
|
||||
table: "team_membership",
|
||||
column: "user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_account_email",
|
||||
schema: "dodo",
|
||||
table: "user_account",
|
||||
column: "email",
|
||||
unique: true,
|
||||
filter: "email IS NOT NULL AND deleted_at_utc IS NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_account_issuer_subject",
|
||||
schema: "dodo",
|
||||
table: "user_account",
|
||||
columns: new[] { "issuer", "subject" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_current",
|
||||
schema: "dodo",
|
||||
table: "user_key",
|
||||
column: "user_id",
|
||||
unique: true,
|
||||
filter: "is_current");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_fingerprint_sha256",
|
||||
schema: "dodo",
|
||||
table: "user_key",
|
||||
column: "fingerprint_sha256",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_user_id_generation",
|
||||
schema: "dodo",
|
||||
table: "user_key",
|
||||
columns: new[] { "user_id", "generation" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_wrap_device_id",
|
||||
schema: "dodo",
|
||||
table: "user_key_wrap",
|
||||
column: "device_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_wrap_user_device",
|
||||
schema: "dodo",
|
||||
table: "user_key_wrap",
|
||||
columns: new[] { "user_id", "device_id" },
|
||||
unique: true,
|
||||
filter: "device_id IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_key_wrap_user_kind",
|
||||
schema: "dodo",
|
||||
table: "user_key_wrap",
|
||||
columns: new[] { "user_id", "kind" },
|
||||
unique: true,
|
||||
filter: "device_id IS NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_vault_owner_user_id",
|
||||
schema: "dodo",
|
||||
table: "vault",
|
||||
column: "owner_user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_vault_team_id",
|
||||
schema: "dodo",
|
||||
table: "vault",
|
||||
column: "team_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_vault_key_grant_recipient_user_id",
|
||||
schema: "dodo",
|
||||
table: "vault_key_grant",
|
||||
column: "recipient_user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_vault_key_grant_vault_id_key_generation_recipient_user_id",
|
||||
schema: "dodo",
|
||||
table: "vault_key_grant",
|
||||
columns: new[] { "vault_id", "key_generation", "recipient_user_id" },
|
||||
unique: true,
|
||||
filter: "revoked_at_utc IS NULL AND recipient_user_id IS NOT NULL");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "host",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "key_log",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "sync_change",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "sync_operation_receipt",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "team_membership",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "user_key",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "user_key_wrap",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "vault_key_grant",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "device",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "vault",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "team",
|
||||
schema: "dodo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "user_account",
|
||||
schema: "dodo");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,968 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using DodoSSH.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DodoSSH.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(DodoDbContext))]
|
||||
partial class DodoDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("dodo")
|
||||
.HasAnnotation("ProductVersion", "10.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "citext");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Device", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("EnrolledAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("enrolled_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastSeenAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_seen_at_utc");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("Platform")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("platform");
|
||||
|
||||
b.Property<byte[]>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("public_key");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_device");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_device_user_id");
|
||||
|
||||
b.ToTable("device", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Host", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<long>("ChangeSequence")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("change_sequence");
|
||||
|
||||
b.Property<Guid?>("ContentKeyId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("content_key_id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid>("CreatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("created_by_user_id");
|
||||
|
||||
b.Property<byte[]>("DataKeyWrap")
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("data_key_wrap");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<Guid?>("GroupId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("group_id");
|
||||
|
||||
b.Property<string>("Hostname")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)")
|
||||
.HasColumnName("hostname");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<byte[]>("Payload")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("payload");
|
||||
|
||||
b.Property<short>("PayloadAadVersion")
|
||||
.HasColumnType("smallint")
|
||||
.HasColumnName("payload_aad_version");
|
||||
|
||||
b.Property<int?>("Port")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("port");
|
||||
|
||||
b.Property<bool>("RelayEnabled")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("relay_enabled");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<Guid>("UpdatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("updated_by_user_id");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.Property<int>("Version")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("version");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_host");
|
||||
|
||||
b.HasIndex("VaultId")
|
||||
.HasDatabaseName("ix_host_vault_live")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.HasIndex("VaultId", "ChangeSequence")
|
||||
.HasDatabaseName("ix_host_vault_id_change_sequence");
|
||||
|
||||
b.ToTable("host", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_host_port_range", "port IS NULL OR (port BETWEEN 1 AND 65535)");
|
||||
|
||||
t.HasCheckConstraint("ck_host_relay_target", "(relay_enabled AND hostname IS NOT NULL AND port IS NOT NULL)\nOR (NOT relay_enabled AND hostname IS NULL AND port IS NULL)");
|
||||
|
||||
t.HasCheckConstraint("ck_host_version", "version >= 1");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.KeyLogEntry", b =>
|
||||
{
|
||||
b.Property<long>("Sequence")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("sequence");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property<long>("Sequence"));
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("EncryptionPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("encryption_public_key");
|
||||
|
||||
b.Property<int>("Generation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("generation");
|
||||
|
||||
b.Property<byte[]>("Hash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("hash");
|
||||
|
||||
b.Property<byte[]>("PreviousHash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("previous_hash");
|
||||
|
||||
b.Property<byte[]>("SigningPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signing_public_key");
|
||||
|
||||
b.Property<byte[]>("StatementSignature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("statement_signature");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Sequence")
|
||||
.HasName("pk_key_log");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_key_log_hash");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_key_log_user_id");
|
||||
|
||||
b.ToTable("key_log", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.SyncChange", b =>
|
||||
{
|
||||
b.Property<long>("Sequence")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("sequence");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property<long>("Sequence"));
|
||||
|
||||
b.Property<Guid>("ActorUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("actor_user_id");
|
||||
|
||||
b.Property<Guid>("EntityId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("entity_id");
|
||||
|
||||
b.Property<int>("EntityType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("entity_type");
|
||||
|
||||
b.Property<DateTimeOffset>("OccurredAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("occurred_at_utc");
|
||||
|
||||
b.Property<int>("Operation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("operation");
|
||||
|
||||
b.Property<int>("Revision")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("revision");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.HasKey("Sequence")
|
||||
.HasName("pk_sync_change");
|
||||
|
||||
b.HasIndex("VaultId", "Sequence")
|
||||
.HasDatabaseName("ix_sync_change_vault_id_sequence");
|
||||
|
||||
b.HasIndex("VaultId", "EntityId", "Sequence")
|
||||
.IsDescending(false, false, true)
|
||||
.HasDatabaseName("ix_sync_change_vault_id_entity_id_sequence");
|
||||
|
||||
b.ToTable("sync_change", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.SyncOperationReceipt", b =>
|
||||
{
|
||||
b.Property<Guid>("OperationId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("operation_id");
|
||||
|
||||
b.Property<long?>("AppliedChangeSequence")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("applied_change_sequence");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<int?>("ResultVersion")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("result_version");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.HasKey("OperationId")
|
||||
.HasName("pk_sync_operation_receipt");
|
||||
|
||||
b.HasIndex("VaultId", "CreatedAtUtc")
|
||||
.HasDatabaseName("ix_sync_operation_receipt_vault_id_created_at_utc");
|
||||
|
||||
b.ToTable("sync_operation_receipt", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Team", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid>("CreatedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("created_by_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("citext")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_team");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_team_slug")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.ToTable("team", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.TeamMembership", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<Guid?>("InvitedByUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("invited_by_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("JoinedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("joined_at_utc");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("role");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<Guid>("TeamId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("team_id");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_team_membership");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_team_membership_user_id");
|
||||
|
||||
b.HasIndex("TeamId", "UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_team_membership_team_id_user_id")
|
||||
.HasFilter("deleted_at_utc IS NULL");
|
||||
|
||||
b.ToTable("team_membership", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("display_name");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(320)
|
||||
.HasColumnType("citext")
|
||||
.HasColumnName("email");
|
||||
|
||||
b.Property<DateTimeOffset?>("EnrolledAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("enrolled_at_utc");
|
||||
|
||||
b.Property<string>("Issuer")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasColumnName("issuer");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastSeenAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_seen_at_utc");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("subject");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_account");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_account_email")
|
||||
.HasFilter("email IS NOT NULL AND deleted_at_utc IS NULL");
|
||||
|
||||
b.HasIndex("Issuer", "Subject")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_account_issuer_subject");
|
||||
|
||||
b.ToTable("user_account", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("EncryptionPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("encryption_public_key");
|
||||
|
||||
b.Property<byte[]>("FingerprintSha256")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("fingerprint_sha256");
|
||||
|
||||
b.Property<int>("Generation")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("generation");
|
||||
|
||||
b.Property<string>("IdentityProviderBinding")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("identity_provider_binding");
|
||||
|
||||
b.Property<bool>("IsCurrent")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_current");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<byte[]>("SigningPublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signing_public_key");
|
||||
|
||||
b.Property<string>("Statement")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("statement");
|
||||
|
||||
b.Property<byte[]>("StatementSignature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("statement_signature");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_key");
|
||||
|
||||
b.HasIndex("FingerprintSha256")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_fingerprint_sha256");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_current")
|
||||
.HasFilter("is_current");
|
||||
|
||||
b.HasIndex("UserId", "Generation")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_user_id_generation");
|
||||
|
||||
b.ToTable("user_key", "dodo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKeyWrap", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<Guid?>("DeviceId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("device_id");
|
||||
|
||||
b.Property<string>("KdfAlgorithm")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)")
|
||||
.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")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("kdf_salt");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("kind");
|
||||
|
||||
b.Property<DateTimeOffset?>("LastUsedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_used_at_utc");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<byte[]>("Wrap")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("wrap");
|
||||
|
||||
b.Property<int>("WrapVersion")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("wrap_version");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_user_key_wrap");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.HasDatabaseName("ix_user_key_wrap_device_id");
|
||||
|
||||
b.HasIndex("UserId", "DeviceId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_wrap_user_device")
|
||||
.HasFilter("device_id IS NOT NULL");
|
||||
|
||||
b.HasIndex("UserId", "Kind")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_user_key_wrap_user_kind")
|
||||
.HasFilter("device_id IS NULL");
|
||||
|
||||
b.ToTable("user_key_wrap", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_user_key_wrap_device", "(kind = 2 AND device_id IS NOT NULL) OR (kind <> 2 AND device_id IS NULL)");
|
||||
|
||||
t.HasCheckConstraint("ck_user_key_wrap_kdf", "(kind IN (1, 3) AND kdf_algorithm IS NOT NULL AND kdf_salt IS NOT NULL\n AND kdf_memory_kibibytes IS NOT NULL AND kdf_passes IS NOT NULL\n AND kdf_parallelism IS NOT NULL)\nOR (kind IN (2, 4) AND kdf_algorithm IS NULL AND kdf_salt IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at_utc");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("OwnerKind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("owner_kind");
|
||||
|
||||
b.Property<Guid?>("OwnerUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("owner_user_id");
|
||||
|
||||
b.Property<int>("RekeyReason")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("rekey_reason");
|
||||
|
||||
b.Property<bool>("RekeyRequired")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("rekey_required");
|
||||
|
||||
b.Property<Guid?>("TeamId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("team_id");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at_utc");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_vault");
|
||||
|
||||
b.HasIndex("OwnerUserId")
|
||||
.HasDatabaseName("ix_vault_owner_user_id");
|
||||
|
||||
b.HasIndex("TeamId")
|
||||
.HasDatabaseName("ix_vault_team_id");
|
||||
|
||||
b.ToTable("vault", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_vault_key_generation", "key_generation >= 1");
|
||||
|
||||
t.HasCheckConstraint("ck_vault_owner", "(owner_kind = 1 AND owner_user_id IS NOT NULL AND team_id IS NULL)\nOR (owner_kind = 2 AND team_id IS NOT NULL AND owner_user_id IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.VaultKeyGrant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at_utc");
|
||||
|
||||
b.Property<byte[]>("GranterKeyFingerprint")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("granter_key_fingerprint");
|
||||
|
||||
b.Property<Guid>("GranterUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("granter_user_id");
|
||||
|
||||
b.Property<int>("KeyGeneration")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("key_generation");
|
||||
|
||||
b.Property<byte[]>("KeyLogHead")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("key_log_head");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("kind");
|
||||
|
||||
b.Property<byte[]>("RecipientKeyFingerprint")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("recipient_key_fingerprint");
|
||||
|
||||
b.Property<Guid?>("RecipientUserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("recipient_user_id");
|
||||
|
||||
b.Property<DateTimeOffset?>("RevokedAtUtc")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("revoked_at_utc");
|
||||
|
||||
b.Property<byte[]>("Signature")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("signature");
|
||||
|
||||
b.Property<int>("State")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("state");
|
||||
|
||||
b.Property<Guid>("VaultId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("vault_id");
|
||||
|
||||
b.Property<byte[]>("WrappedKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("wrapped_key");
|
||||
|
||||
b.Property<uint>("xmin")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("xid")
|
||||
.HasColumnName("xmin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_vault_key_grant");
|
||||
|
||||
b.HasIndex("RecipientUserId")
|
||||
.HasDatabaseName("ix_vault_key_grant_recipient_user_id");
|
||||
|
||||
b.HasIndex("VaultId", "KeyGeneration", "RecipientUserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_vault_key_grant_vault_id_key_generation_recipient_user_id")
|
||||
.HasFilter("revoked_at_utc IS NULL AND recipient_user_id IS NOT NULL");
|
||||
|
||||
b.ToTable("vault_key_grant", "dodo", t =>
|
||||
{
|
||||
t.HasCheckConstraint("ck_vault_key_grant_recipient", "(kind = 1 AND recipient_user_id IS NOT NULL) OR (kind <> 1 AND recipient_user_id IS NULL)");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("Devices")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_device_users_user_id");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Host", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Vault", "Vault")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("VaultId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_host_vaults_vault_id");
|
||||
|
||||
b.Navigation("Vault");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.TeamMembership", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Team", "Team")
|
||||
.WithMany("Memberships")
|
||||
.HasForeignKey("TeamId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_team_membership_team_team_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_team_membership_users_user_id");
|
||||
|
||||
b.Navigation("Team");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKey", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("Keys")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_user_key_user_account_user_id");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserKeyWrap", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_user_key_wrap_device_device_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "User")
|
||||
.WithMany("KeyWraps")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_user_key_wrap_user_account_user_id");
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "OwnerUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerUserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.HasConstraintName("fk_vault_user_account_owner_user_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.Team", "Team")
|
||||
.WithMany()
|
||||
.HasForeignKey("TeamId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.HasConstraintName("fk_vault_team_team_id");
|
||||
|
||||
b.Navigation("OwnerUser");
|
||||
|
||||
b.Navigation("Team");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.VaultKeyGrant", b =>
|
||||
{
|
||||
b.HasOne("DodoSSH.Domain.UserAccount", "RecipientUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_vault_key_grant_user_account_recipient_user_id");
|
||||
|
||||
b.HasOne("DodoSSH.Domain.Vault", "Vault")
|
||||
.WithMany("KeyGrants")
|
||||
.HasForeignKey("VaultId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_vault_key_grant_vault_vault_id");
|
||||
|
||||
b.Navigation("RecipientUser");
|
||||
|
||||
b.Navigation("Vault");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Team", b =>
|
||||
{
|
||||
b.Navigation("Memberships");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.UserAccount", b =>
|
||||
{
|
||||
b.Navigation("Devices");
|
||||
|
||||
b.Navigation("KeyWraps");
|
||||
|
||||
b.Navigation("Keys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DodoSSH.Domain.Vault", b =>
|
||||
{
|
||||
b.Navigation("Hosts");
|
||||
|
||||
b.Navigation("KeyGrants");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user