From 45fcffb6a3f3a932b3267e8821d51af843ae967e Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Tue, 31 Oct 2023 15:37:58 +0200 Subject: [PATCH 1/2] fix: Conversation Proteus verification --- .../com/wire/kalium/persistence/Clients.sq | 7 +- .../wire/kalium/persistence/Conversations.sq | 1 + .../com/wire/kalium/persistence/Members.sq | 32 ++++++++ .../src/commonMain/db_user/migrations/64.sqm | 78 +++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 persistence/src/commonMain/db_user/migrations/64.sqm diff --git a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Clients.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Clients.sq index 8650e6663ed..1e8c0a90576 100644 --- a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Clients.sq +++ b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Clients.sq @@ -85,14 +85,17 @@ AFTER UPDATE ON Client BEGIN UPDATE Conversation SET proteus_verification_status = (CASE (new.is_verified) WHEN 1 THEN "VERIFIED" ELSE "DEGRADED" END) WHERE qualified_id IN ( - SELECT id FROM (SELECT conv.qualified_id AS id, conv.proteus_verification_status AS verificationStatus, (COUNT(*) = SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END)) AS isActuallyVerified + SELECT id FROM (SELECT + conv.qualified_id AS id, + conv.proteus_verification_status AS verificationStatus, + -- +1 is to not count a current client, for checking if conversation is verified + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END)) AS isActuallyVerified FROM Conversation AS conv LEFT JOIN Member AS mem ON conv.qualified_id = mem.conversation LEFT JOIN Client AS client ON client.user_id = mem.user WHERE conv.qualified_id IN (SELECT Member.conversation FROM Member LEFT JOIN Client ON Client.user_id = Member.user WHERE Client.id = new.id) - AND mem.user IS NOT (SELECT SelfUser.id FROM SelfUser LIMIT 1) GROUP BY conv.qualified_id) WHERE (CASE (verificationStatus) WHEN "VERIFIED" THEN 1 ELSE 0 END) != isActuallyVerified ); diff --git a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq index 57b849a39ac..bc6eb9d1913 100644 --- a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq +++ b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq @@ -412,6 +412,7 @@ SELECT changes(); CREATE TRIGGER addMessageAfterProteusVerificationStatusChange AFTER UPDATE ON Conversation WHEN new.proteus_verification_status != old.proteus_verification_status +AND (new.proteus_verification_status = "VERIFIED" OR old.proteus_verification_status = "VERIFIED") BEGIN INSERT OR IGNORE INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, visibility) VALUES( diff --git a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Members.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Members.sq index ddcb4636133..e7c4e72c91c 100644 --- a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Members.sq +++ b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Members.sq @@ -83,3 +83,35 @@ SELECT mem.* FROM Member AS mem JOIN Conversation AS con ON con.qualified_id = mem.conversation JOIN User AS usr ON usr.qualified_id = mem.user WHERE con.type == 'ONE_ON_ONE' AND user LIKE ('%@' || :domain) AND usr.defederated == 0; + +CREATE TRIGGER updateConversationProteusVerificationStatusAfterMemeberChange +AFTER INSERT ON Member +BEGIN + UPDATE Conversation + SET proteus_verification_status = + (CASE (SELECT + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END) AND COUNT(*) > 1) + FROM Member AS mem + LEFT JOIN Client AS client ON client.user_id = mem.user + WHERE mem.conversation = new.conversation + GROUP BY mem.conversation) + WHEN 1 THEN "VERIFIED" + ELSE "DEGRADED" END) + WHERE qualified_id = new.conversation; +END; + +CREATE TRIGGER updateConversationProteusVerificationStatusAfterMemeberDelete +AFTER DELETE ON Member +BEGIN + UPDATE Conversation + SET proteus_verification_status = + (CASE (SELECT + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END) AND COUNT(*) > 1) + FROM Member AS mem + LEFT JOIN Client AS client ON client.user_id = mem.user + WHERE mem.conversation = old.conversation + GROUP BY mem.conversation) + WHEN 1 THEN "VERIFIED" + ELSE "DEGRADED" END) + WHERE qualified_id = old.conversation; +END; diff --git a/persistence/src/commonMain/db_user/migrations/64.sqm b/persistence/src/commonMain/db_user/migrations/64.sqm new file mode 100644 index 00000000000..a936a9e9160 --- /dev/null +++ b/persistence/src/commonMain/db_user/migrations/64.sqm @@ -0,0 +1,78 @@ +DROP TRIGGER IF EXISTS updateConversationProteusVerificationStatus; +DROP TRIGGER IF EXISTS addMessageAfterProteusVerificationStatusChange; + +CREATE TRIGGER updateConversationProteusVerificationStatus +AFTER UPDATE ON Client +BEGIN + UPDATE Conversation SET proteus_verification_status = (CASE (new.is_verified) WHEN 1 THEN "VERIFIED" ELSE "DEGRADED" END) + WHERE qualified_id IN ( + SELECT id FROM (SELECT + conv.qualified_id AS id, + conv.proteus_verification_status AS verificationStatus, + -- +1 is to not count a current client, for checking if conversation is verified + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END)) AS isActuallyVerified + FROM Conversation AS conv + LEFT JOIN Member AS mem ON conv.qualified_id = mem.conversation + LEFT JOIN Client AS client ON client.user_id = mem.user + WHERE conv.qualified_id IN (SELECT Member.conversation FROM Member + LEFT JOIN Client ON Client.user_id = Member.user + WHERE Client.id = new.id) + GROUP BY conv.qualified_id) + WHERE (CASE (verificationStatus) WHEN "VERIFIED" THEN 1 ELSE 0 END) != isActuallyVerified + ); +END; + +CREATE TRIGGER addMessageAfterProteusVerificationStatusChange +AFTER UPDATE ON Conversation +WHEN new.proteus_verification_status != old.proteus_verification_status +AND (new.proteus_verification_status = "VERIFIED" OR old.proteus_verification_status = "VERIFIED") +BEGIN + INSERT OR IGNORE INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, visibility) + VALUES( + (SELECT lower(hex(randomblob(4)) || '-' || lower(hex(randomblob(2))) || '-4' || + substr(lower(hex(randomblob(2))),2) || '-a' || substr(lower(hex(randomblob(2))),2) + || '-' || lower(hex(randomblob(6))))), + (CASE (new.proteus_verification_status) + WHEN "VERIFIED" THEN "CONVERSATION_VERIFIED_PROTEUS" + ELSE "CONVERSATION_DEGRADED_PROTEUS" END + ), + new.qualified_id, + (SELECT CAST((julianday('now') - 2440587.5) * 86400 * 1000 AS INTEGER)), + (SELECT SelfUser.id FROM SelfUser LIMIT 1), + (SELECT Client.id FROM Client WHERE Client.user_id = (SELECT SelfUser.id FROM SelfUser LIMIT 1) LIMIT 1), + "SENT", + "VISIBLE" + ); +END; + +CREATE TRIGGER updateConversationProteusVerificationStatusAfterMemeberChange +AFTER INSERT ON Member +BEGIN + UPDATE Conversation + SET proteus_verification_status = + (CASE (SELECT + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END) AND COUNT(*) > 1) + FROM Member AS mem + LEFT JOIN Client AS client ON client.user_id = mem.user + WHERE mem.conversation = new.conversation + GROUP BY mem.conversation) + WHEN 1 THEN "VERIFIED" + ELSE "DEGRADED" END) + WHERE qualified_id = new.conversation; +END; + +CREATE TRIGGER updateConversationProteusVerificationStatusAfterMemeberDelete +AFTER DELETE ON Member +BEGIN + UPDATE Conversation + SET proteus_verification_status = + (CASE (SELECT + (COUNT(*) = 1 + SUM(CASE WHEN client.is_verified = 1 THEN 1 ELSE 0 END) AND COUNT(*) > 1) + FROM Member AS mem + LEFT JOIN Client AS client ON client.user_id = mem.user + WHERE mem.conversation = old.conversation + GROUP BY mem.conversation) + WHEN 1 THEN "VERIFIED" + ELSE "DEGRADED" END) + WHERE qualified_id = old.conversation; +END; From 8ace6a3c141c3719e6f10ab2a840b550fb261c2b Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Tue, 31 Oct 2023 18:01:57 +0200 Subject: [PATCH 2/2] Fixed test --- .../kalium/persistence/dao/ConversationDAOTest.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/ConversationDAOTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/ConversationDAOTest.kt index 2772c21f75a..8d526d8b585 100644 --- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/ConversationDAOTest.kt +++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/ConversationDAOTest.kt @@ -1649,7 +1649,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedDateTime = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED, userSupportedProtocols = if (type == ConversationEntity.Type.ONE_ON_ONE) userEntity?.supportedProtocols else null, userActiveOneOnOneConversationId = null, ) @@ -1697,7 +1697,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val conversationEntity2 = ConversationEntity( QualifiedIDEntity("2", "wire.com"), @@ -1724,7 +1724,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val conversationEntity3 = ConversationEntity( @@ -1754,7 +1754,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val conversationEntity4 = ConversationEntity( @@ -1784,7 +1784,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val conversationEntity5 = ConversationEntity( QualifiedIDEntity("5", "wire.com"), @@ -1805,7 +1805,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val conversationEntity6 = ConversationEntity( QualifiedIDEntity("6", "wire.com"), @@ -1834,7 +1834,7 @@ class ConversationDAOTest : BaseDatabaseTest() { archived = false, archivedInstant = null, mlsVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED, - proteusVerificationStatus = ConversationEntity.VerificationStatus.NOT_VERIFIED + proteusVerificationStatus = ConversationEntity.VerificationStatus.DEGRADED ) val member1 = MemberEntity(user1.id, MemberEntity.Role.Admin)