@@ -143,6 +143,43 @@ impl ContactId {
143
143
. await ?;
144
144
Ok ( ( ) )
145
145
}
146
+
147
+ /// Returns contact adress.
148
+ pub async fn addr ( & self , context : & Context ) -> Result < String > {
149
+ let addr = context
150
+ . sql
151
+ . query_row ( "SELECT addr FROM contacts WHERE id=?" , ( self , ) , |row| {
152
+ let addr: String = row. get ( 0 ) ?;
153
+ Ok ( addr)
154
+ } )
155
+ . await ?;
156
+ Ok ( addr)
157
+ }
158
+
159
+ /// Resets encryption with the contact.
160
+ ///
161
+ /// Effect is similar to receiving a message without Autocrypt header
162
+ /// from the contact, but this action is triggered manually by the user.
163
+ ///
164
+ /// For example, this will result in sending the next message
165
+ /// to 1:1 chat unencrypted, but will not remove existing verified keys.
166
+ pub async fn reset_encryption ( self , context : & Context ) -> Result < ( ) > {
167
+ let now = time ( ) ;
168
+
169
+ let addr = self . addr ( context) . await ?;
170
+ if let Some ( mut peerstate) = Peerstate :: from_addr ( context, & addr) . await ? {
171
+ peerstate. degrade_encryption ( now) ;
172
+ peerstate. save_to_db ( & context. sql ) . await ?;
173
+ }
174
+
175
+ // Reset 1:1 chat protection.
176
+ if let Some ( chat_id) = ChatId :: lookup_by_contact ( context, self ) . await ? {
177
+ chat_id
178
+ . set_protection ( context, ProtectionStatus :: Unprotected , now, Some ( self ) )
179
+ . await ?;
180
+ }
181
+ Ok ( ( ) )
182
+ }
146
183
}
147
184
148
185
impl fmt:: Display for ContactId {
@@ -3152,4 +3189,59 @@ Until the false-positive is fixed:
3152
3189
3153
3190
Ok ( ( ) )
3154
3191
}
3192
+
3193
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
3194
+ async fn test_reset_encryption ( ) -> Result < ( ) > {
3195
+ let mut tcm = TestContextManager :: new ( ) ;
3196
+ let alice = & tcm. alice ( ) . await ;
3197
+ let bob = & tcm. bob ( ) . await ;
3198
+
3199
+ let msg = tcm. send_recv_accept ( alice, bob, "Hello!" ) . await ;
3200
+ assert_eq ! ( msg. get_showpadlock( ) , false ) ;
3201
+
3202
+ let msg = tcm. send_recv ( bob, alice, "Hi!" ) . await ;
3203
+ assert_eq ! ( msg. get_showpadlock( ) , true ) ;
3204
+ let alice_bob_contact_id = msg. from_id ;
3205
+
3206
+ alice_bob_contact_id. reset_encryption ( alice) . await ?;
3207
+
3208
+ let msg = tcm. send_recv ( alice, bob, "Unencrypted" ) . await ;
3209
+ assert_eq ! ( msg. get_showpadlock( ) , false ) ;
3210
+
3211
+ Ok ( ( ) )
3212
+ }
3213
+
3214
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
3215
+ async fn test_reset_verified_encryption ( ) -> Result < ( ) > {
3216
+ let mut tcm = TestContextManager :: new ( ) ;
3217
+ let alice = & tcm. alice ( ) . await ;
3218
+ let bob = & tcm. bob ( ) . await ;
3219
+
3220
+ tcm. execute_securejoin ( bob, alice) . await ;
3221
+
3222
+ let msg = tcm. send_recv ( bob, alice, "Encrypted" ) . await ;
3223
+ assert_eq ! ( msg. get_showpadlock( ) , true ) ;
3224
+
3225
+ let alice_bob_chat_id = msg. chat_id ;
3226
+ let alice_bob_contact_id = msg. from_id ;
3227
+ alice_bob_contact_id. reset_encryption ( alice) . await ?;
3228
+
3229
+ // Check that the contact is still verified after resetting encryption.
3230
+ let alice_bob_contact = Contact :: get_by_id ( alice, alice_bob_contact_id) . await ?;
3231
+ assert_eq ! ( alice_bob_contact. is_verified( alice) . await ?, true ) ;
3232
+
3233
+ // 1:1 chat and profile is no longer verified.
3234
+ assert_eq ! ( alice_bob_contact. is_profile_verified( alice) . await ?, false ) ;
3235
+
3236
+ let info_msg = alice. get_last_msg_in ( alice_bob_chat_id) . await ;
3237
+ assert_eq ! (
3238
+ info_msg. text,
3239
+ "[email protected] sent a message from another device."
3240
+ ) ;
3241
+
3242
+ let msg = tcm. send_recv ( alice, bob, "Unencrypted" ) . await ;
3243
+ assert_eq ! ( msg. get_showpadlock( ) , false ) ;
3244
+
3245
+ Ok ( ( ) )
3246
+ }
3155
3247
}
0 commit comments