From 291f6c1cec242ce6da98b81dbf4bd0b3ca5662b6 Mon Sep 17 00:00:00 2001 From: Devon Hillard Date: Wed, 11 Mar 2026 18:36:50 -0600 Subject: [PATCH 1/2] fix: Remove non-portable BLOB columnDefinition from WebAuthnCredential Remove hardcoded `columnDefinition = "BLOB"` from three byte[] fields in WebAuthnCredential. The `@Lob` annotation already handles dialect- appropriate type mapping (BLOB for MySQL, bytea for PostgreSQL, etc.). The explicit columnDefinition bypassed Hibernate's dialect translation, causing DDL failures on PostgreSQL and other non-MySQL databases. Fixes #274 --- .../spring/user/persistence/model/WebAuthnCredential.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java b/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java index 57b84ab..5819aa2 100644 --- a/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java +++ b/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java @@ -32,7 +32,7 @@ public class WebAuthnCredential { /** COSE-encoded public key (typically 77-300 bytes, RSA keys can be larger). */ @Lob - @Column(name = "public_key", nullable = false, columnDefinition = "BLOB") + @Column(name = "public_key", nullable = false) private byte[] publicKey; /** Counter to detect cloned authenticators. */ @@ -61,12 +61,12 @@ public class WebAuthnCredential { /** Attestation data from registration (can be several KB). */ @Lob - @Column(name = "attestation_object", columnDefinition = "BLOB") + @Column(name = "attestation_object") private byte[] attestationObject; /** Client data JSON from registration (can be several KB). */ @Lob - @Column(name = "attestation_client_data_json", columnDefinition = "BLOB") + @Column(name = "attestation_client_data_json") private byte[] attestationClientDataJson; /** Creation timestamp. */ From 8aa976f1b3cfe44465b223da8c8c6777bb3811d2 Mon Sep 17 00:00:00 2001 From: Devon Hillard Date: Wed, 11 Mar 2026 18:46:16 -0600 Subject: [PATCH 2/2] fix: Use plain byte[] instead of @Lob for portable WebAuthn columns Replace `@Lob @Column(columnDefinition = "BLOB")` with plain `byte[]` and explicit `@Column(length = ...)` on the three binary fields in WebAuthnCredential. `@Lob` on byte[] in Hibernate 7 generates literal `blob` in DDL, which bypasses dialect translation and fails on PostgreSQL (no `blob` type). Plain byte[] lets each dialect choose the correct native type: `bytea` on PostgreSQL, `varbinary`/`mediumblob` on MySQL. Verified DDL generation against a real PostgreSQL 16 instance and confirmed all three columns map to `bytea`. Full H2 test suite passes with no regressions. Fixes #274 --- .../user/persistence/model/WebAuthnCredential.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java b/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java index 5819aa2..5ee98c7 100644 --- a/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java +++ b/src/main/java/com/digitalsanctuary/spring/user/persistence/model/WebAuthnCredential.java @@ -6,7 +6,6 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; -import jakarta.persistence.Lob; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.Data; @@ -31,8 +30,7 @@ public class WebAuthnCredential { private WebAuthnUserEntity userEntity; /** COSE-encoded public key (typically 77-300 bytes, RSA keys can be larger). */ - @Lob - @Column(name = "public_key", nullable = false) + @Column(name = "public_key", nullable = false, length = 2048) private byte[] publicKey; /** Counter to detect cloned authenticators. */ @@ -60,13 +58,11 @@ public class WebAuthnCredential { private boolean backupState; /** Attestation data from registration (can be several KB). */ - @Lob - @Column(name = "attestation_object") + @Column(name = "attestation_object", length = 65536) private byte[] attestationObject; /** Client data JSON from registration (can be several KB). */ - @Lob - @Column(name = "attestation_client_data_json") + @Column(name = "attestation_client_data_json", length = 65536) private byte[] attestationClientDataJson; /** Creation timestamp. */