diff --git a/testing/matrix-sdk-test/src/test_json/keys_query.rs b/testing/matrix-sdk-test/src/test_json/keys_query.rs new file mode 100644 index 000000000..e9b25c7d4 --- /dev/null +++ b/testing/matrix-sdk-test/src/test_json/keys_query.rs @@ -0,0 +1,204 @@ +// Copyright 2024 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Templates for simulating responses to +//! `POST /_matrix/client/v3/keys/query` +//! requests. + +use std::{collections::HashMap, iter}; + +use ruma::{ + api::client::keys::get_keys::v3::Response as KeyQueryResponse, device_id, user_id, DeviceId, + UserId, +}; +use serde_json::json; + +use crate::ruma_response_from_json; + +pub struct KeysQueryUser { + pub user_id: &'static UserId, + pub device_id: &'static DeviceId, + device_key_curve25519: &'static str, + device_key_ed22519: &'static str, + device_signature: &'static str, + device_signature_2_name: Option<&'static str>, + device_signature_2_signature: Option<&'static str>, + master_key_name: Option<&'static str>, + master_key_signature: Option<&'static str>, + master_key_device_signature: Option<&'static str>, + self_signing_key_name: Option<&'static str>, + self_signing_key_signature: Option<&'static str>, +} + +impl KeysQueryUser { + pub(crate) fn bob_a() -> Self { + Self { + user_id: user_id!("@bob:localhost"), + device_id: device_id!("GYKSNAWLVK"), + device_key_curve25519: "dBcZBzQaiQYWf6rBPh2QypIOB/dxSoTeyaFaxNNbeHs", + device_key_ed22519: "6melQNnhoI9sT2b4VzNPAwa8aB179ym45fON8Yo7kVk", + device_signature: "Fk45zHAbrd+1j9wZXLjL2Y/+DU/Mnz9yuvlfYBOOT7qExN2Jdud+5BAuNs8nZ/caS4wTF39Kg3zQpzaGERoCBg", + device_signature_2_name: Some("dO4gmBNW7WC0bXBK81j8uh4me6085fP+keoOm0pH3gw"), + device_signature_2_signature: Some("md0Pa1MYlneFb1fp6KCsvZpi2ySb6/G+ULoCbQDWBeDxNEcoNMzf7PEKY04UToCZKUU4LifvRWmiWFDanOlkCQ"), + master_key_name: Some("/mULSzYNTdHJOBWnBmsvDHhqdHQcWnXRHHmqwzwC7DY"), + master_key_signature: Some("6vGDbPO5XzlcwbU3aV+kcck+iHHEBtX85ow2gW5U05/DZdtda/JNVa5Nn7B9lQHNnnrMqt1sX00y/JrIkSS1Aw"), + master_key_device_signature: Some("jLxmUPr0Ny2Ai9+NGKGhed9BAuKikOc7r6gr7MQVawePYS95w8NJ8Tzaq9zFFOmIiojACNdQ/ksy3QAdwD6vBQ"), + self_signing_key_name: Some("dO4gmBNW7WC0bXBK81j8uh4me6085fP+keoOm0pH3gw"), + self_signing_key_signature: Some("7md6mwjUK8zjintmffJ0+kImC59/Y8PdySy99EZz5Neu+VMX3LT7txhKO2gC/hmDduRw+JGfGXIiDxR7GmQqDw"), + } + } + + pub(crate) fn bob_b() -> Self { + Self { + user_id: user_id!("@bob:localhost"), + device_id: device_id!("ATWKQFSFRN"), + device_key_curve25519: "CY0TWVK1/Kj3ZADuBcGe3UKvpT+IKAPMUsMeJhSDqno", + device_key_ed22519: "TyTQqd6j2JlWZh97r+kTYuCbvqnPoNwO6EGovYsjY00", + device_signature: "BQ9Gp0p+6srF+c8OyruqKKd9R4yaub3THYAyyBB/7X/rG8BwcAqFynzl1aGyFYun4Q+087a5OSiglCXI+/kQAA", + device_signature_2_name: Some("At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc"), + device_signature_2_signature: Some("TWmDPaG7t0rZ6luauonELD3dmBDTIRryqXhgsIQRiGint2rJdic8RVyZ6a61bgu6mtBjfvU3prqMNp6sVi16Cg"), + master_key_name: Some("NmI78hY54kE7OZsIjbRE/iCox59t4nzScCNEO6fvtY4"), + master_key_signature: Some("xqLhC3sIUci1W2CNVW7HZWXreQApgjv2RDwB0WPiMd1P4vbZ/qJM0KWqK2piGPWliPi8YVREMrg216KXM3IhCA"), + master_key_device_signature: Some("MBOzCKYPQLQMpBY2lFZJ4c8451xJfQCdhPBb1AHlTUSxKFiWi6V+k1oRRnhQein/PjkIY7ZO+HoOrIeOtbRMAw"), + self_signing_key_name: Some("At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc"), + self_signing_key_signature: Some("Ls6CeoA4LoPCHuSwG96kbhd1dEV09TgdMROIZi6vFz/MT9Wtik6joQi/tQ3zCwIZCSR53ksLO4jG1DD31AiBAA"), + } + } + + pub(crate) fn bob_c() -> Self { + Self { + user_id: user_id!("@bob:localhost"), + device_id: device_id!("OPABMDDXGX"), + device_key_curve25519: "O6bwa9Op0E+PQPCrbTOfdYwU+j95RRPhXIHuNpe94ns", + device_key_ed22519: "DvjkSNOM9XrR1gWrr2YSDvTnwnLIgKDMRr5v8HgMKak", + device_signature: "o+BBnw/SIJWxSf799Adq6jEl9X3lwCg5MJkS8GlfId+pW3ReEETK0l+9bhCAgBsNSKRtB/fmZQBhjMx4FJr+BA", + device_signature_2_name: None, + device_signature_2_signature: None, + master_key_name: None, + master_key_signature: None, + master_key_device_signature: None, + self_signing_key_name: None, + self_signing_key_signature: None, + } + } +} + +pub fn keys_query(user: &KeysQueryUser, signed_device_users: &[KeysQueryUser]) -> KeyQueryResponse { + let device_keys = iter::once((user.user_id, device_keys(user, signed_device_users))); + + let data = json!({ + "device_keys": to_object(device_keys), + "failures": {}, + "master_keys": master_keys(user), + "self_signing_keys": self_signing_keys(user), + "user_signing_keys": {} + }); + ruma_response_from_json(&data) +} + +pub fn self_signing_keys(user: &KeysQueryUser) -> serde_json::Value { + if let (Some(self_signing_key_name), Some(self_signing_key_signature)) = + (user.self_signing_key_name, user.self_signing_key_signature) + { + let master_key_name = user + .master_key_name + .expect("Missing master key name when we have self_signing_key_name"); + + json!({ + user.user_id: { + "keys": { + &format!("ed25519:{}", self_signing_key_name): self_signing_key_name + }, + "signatures": { + "@bob:localhost": { + &format!("ed25519:{}", master_key_name): self_signing_key_signature, + } + }, + "usage": [ "self_signing" ], + "user_id": "@bob:localhost" + } + }) + } else { + json!({}) + } +} + +pub fn master_keys(user: &KeysQueryUser) -> serde_json::Value { + if let (Some(master_key_name), Some(master_key_signature), Some(master_key_device_signature)) = + (user.master_key_name, user.master_key_signature, user.master_key_device_signature) + { + json!({ + user.user_id: { + "keys": { &format!("ed25519:{}", master_key_name): master_key_name }, + "signatures": { + user.user_id: { + &format!("ed25519:{}", master_key_name): master_key_signature, + &format!("ed25519:{}", user.device_id): master_key_device_signature + } + }, + "usage": [ "master" ], + "user_id": user.user_id + } + }) + } else { + json!({}) + } +} + +pub fn device_keys_payload(user: &KeysQueryUser) -> serde_json::Value { + let mut signatures = HashMap::new(); + signatures.insert(format!("ed25519:{}", user.device_id), user.device_signature); + + if let (Some(device_signature_2_name), Some(device_signature_2_signature)) = + (user.device_signature_2_name, user.device_signature_2_signature) + { + signatures + .insert(format!("ed25519:{}", device_signature_2_name), device_signature_2_signature); + } + + json!({ + "algorithms": [ + "m.olm.v1.curve25519-aes-sha2", + "m.megolm.v1.aes-sha2" + ], + "device_id": user.device_id, + "keys": { + &format!("curve25519:{}", user.device_id): user.device_key_curve25519, + &format!("ed25519:{}", user.device_id): user.device_key_ed22519, + }, + "signatures": { + user.user_id: signatures + }, + "user_id": user.user_id, + }) +} + +fn device_keys(user: &KeysQueryUser, signed_device_users: &[KeysQueryUser]) -> serde_json::Value { + let mut ret = HashMap::new(); + + ret.insert(user.device_id, device_keys_payload(user)); + + for other in signed_device_users { + ret.insert(other.device_id, device_keys_payload(other)); + } + + json!(ret) +} + +fn to_object( + items: impl Iterator, +) -> serde_json::Value { + let mp: HashMap<&'static UserId, serde_json::Value> = items.collect(); + serde_json::to_value(mp).unwrap() +} diff --git a/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs b/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs index 4c357acc7..d0ac75929 100644 --- a/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs +++ b/testing/matrix-sdk-test/src/test_json/keys_query_sets.rs @@ -4,7 +4,11 @@ use ruma::{ }; use serde_json::{json, Value}; -use crate::ruma_response_from_json; +use super::keys_query::{keys_query, master_keys, KeysQueryUser}; +use crate::{ + ruma_response_from_json, + test_json::keys_query::{device_keys_payload, self_signing_keys}, +}; /// This set of keys/query response was generated using a local synapse. /// Each users was created, device added according to needs and the payload @@ -447,207 +451,64 @@ impl KeyDistributionTestData { /// For user @bob, several payloads with no identities then identity A and B. pub struct IdentityChangeDataSet {} -#[allow(dead_code)] impl IdentityChangeDataSet { pub fn user_id() -> &'static UserId { - user_id!("@bob:localhost") + // All 3 bobs have the same user id + assert_eq!(KeysQueryUser::bob_a().user_id, KeysQueryUser::bob_b().user_id); + assert_eq!(KeysQueryUser::bob_a().user_id, KeysQueryUser::bob_c().user_id); + + KeysQueryUser::bob_a().user_id } - pub fn first_device_id() -> &'static DeviceId { - device_id!("GYKSNAWLVK") + pub fn device_a() -> &'static DeviceId { + KeysQueryUser::bob_a().device_id } - pub fn second_device_id() -> &'static DeviceId { - device_id!("ATWKQFSFRN") + pub fn device_b() -> &'static DeviceId { + KeysQueryUser::bob_b().device_id } - pub fn third_device_id() -> &'static DeviceId { - device_id!("OPABMDDXGX") - } - - fn device_keys_payload_1_signed_by_a() -> Value { - json!({ - "algorithms": [ - "m.olm.v1.curve25519-aes-sha2", - "m.megolm.v1.aes-sha2" - ], - "device_id": "GYKSNAWLVK", - "keys": { - "curve25519:GYKSNAWLVK": "dBcZBzQaiQYWf6rBPh2QypIOB/dxSoTeyaFaxNNbeHs", - "ed25519:GYKSNAWLVK": "6melQNnhoI9sT2b4VzNPAwa8aB179ym45fON8Yo7kVk" - }, - "signatures": { - "@bob:localhost": { - "ed25519:GYKSNAWLVK": "Fk45zHAbrd+1j9wZXLjL2Y/+DU/Mnz9yuvlfYBOOT7qExN2Jdud+5BAuNs8nZ/caS4wTF39Kg3zQpzaGERoCBg", - "ed25519:dO4gmBNW7WC0bXBK81j8uh4me6085fP+keoOm0pH3gw": "md0Pa1MYlneFb1fp6KCsvZpi2ySb6/G+ULoCbQDWBeDxNEcoNMzf7PEKY04UToCZKUU4LifvRWmiWFDanOlkCQ" - } - }, - "user_id": "@bob:localhost", - }) + pub fn device_c() -> &'static DeviceId { + KeysQueryUser::bob_c().device_id } pub fn msk_a() -> Value { - json!({ - "@bob:localhost": { - "keys": { - "ed25519:/mULSzYNTdHJOBWnBmsvDHhqdHQcWnXRHHmqwzwC7DY": "/mULSzYNTdHJOBWnBmsvDHhqdHQcWnXRHHmqwzwC7DY" - }, - "signatures": { - "@bob:localhost": { - "ed25519:/mULSzYNTdHJOBWnBmsvDHhqdHQcWnXRHHmqwzwC7DY": "6vGDbPO5XzlcwbU3aV+kcck+iHHEBtX85ow2gW5U05/DZdtda/JNVa5Nn7B9lQHNnnrMqt1sX00y/JrIkSS1Aw", - "ed25519:GYKSNAWLVK": "jLxmUPr0Ny2Ai9+NGKGhed9BAuKikOc7r6gr7MQVawePYS95w8NJ8Tzaq9zFFOmIiojACNdQ/ksy3QAdwD6vBQ" - } - }, - "usage": [ - "master" - ], - "user_id": "@bob:localhost" - } - }) + master_keys(&KeysQueryUser::bob_a()) } pub fn ssk_a() -> Value { - json!({ - "@bob:localhost": { - "keys": { - "ed25519:dO4gmBNW7WC0bXBK81j8uh4me6085fP+keoOm0pH3gw": "dO4gmBNW7WC0bXBK81j8uh4me6085fP+keoOm0pH3gw" - }, - "signatures": { - "@bob:localhost": { - "ed25519:/mULSzYNTdHJOBWnBmsvDHhqdHQcWnXRHHmqwzwC7DY": "7md6mwjUK8zjintmffJ0+kImC59/Y8PdySy99EZz5Neu+VMX3LT7txhKO2gC/hmDduRw+JGfGXIiDxR7GmQqDw" - } - }, - "usage": [ - "self_signing" - ], - "user_id": "@bob:localhost" - } - }) + self_signing_keys(&KeysQueryUser::bob_a()) } + /// A key query with an identity (Ia), and a first device `GYKSNAWLVK` /// signed by Ia. pub fn key_query_with_identity_a() -> KeyQueryResponse { - let data = json!({ - "device_keys": { - "@bob:localhost": { - "GYKSNAWLVK": Self::device_keys_payload_1_signed_by_a() - } - }, - "failures": {}, - "master_keys": Self::msk_a(), - "self_signing_keys": Self::ssk_a(), - "user_signing_keys": {} - }); - ruma_response_from_json(&data) + keys_query(&KeysQueryUser::bob_a(), &[]) } pub fn msk_b() -> Value { - json!({ - "@bob:localhost": { - "keys": { - "ed25519:NmI78hY54kE7OZsIjbRE/iCox59t4nzScCNEO6fvtY4": "NmI78hY54kE7OZsIjbRE/iCox59t4nzScCNEO6fvtY4" - }, - "signatures": { - "@bob:localhost": { - "ed25519:ATWKQFSFRN": "MBOzCKYPQLQMpBY2lFZJ4c8451xJfQCdhPBb1AHlTUSxKFiWi6V+k1oRRnhQein/PjkIY7ZO+HoOrIeOtbRMAw", - "ed25519:NmI78hY54kE7OZsIjbRE/iCox59t4nzScCNEO6fvtY4": "xqLhC3sIUci1W2CNVW7HZWXreQApgjv2RDwB0WPiMd1P4vbZ/qJM0KWqK2piGPWliPi8YVREMrg216KXM3IhCA" - } - }, - "usage": [ - "master" - ], - "user_id": "@bob:localhost" - } - }) + master_keys(&KeysQueryUser::bob_b()) } pub fn ssk_b() -> Value { - json!({ - "@bob:localhost": { - "keys": { - "ed25519:At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc": "At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc" - }, - "signatures": { - "@bob:localhost": { - "ed25519:NmI78hY54kE7OZsIjbRE/iCox59t4nzScCNEO6fvtY4": "Ls6CeoA4LoPCHuSwG96kbhd1dEV09TgdMROIZi6vFz/MT9Wtik6joQi/tQ3zCwIZCSR53ksLO4jG1DD31AiBAA" - } - }, - "usage": [ - "self_signing" - ], - "user_id": "@bob:localhost" - } - }) + self_signing_keys(&KeysQueryUser::bob_b()) } pub fn device_keys_payload_2_signed_by_b() -> Value { - json!({ - "algorithms": [ - "m.olm.v1.curve25519-aes-sha2", - "m.megolm.v1.aes-sha2" - ], - "device_id": "ATWKQFSFRN", - "keys": { - "curve25519:ATWKQFSFRN": "CY0TWVK1/Kj3ZADuBcGe3UKvpT+IKAPMUsMeJhSDqno", - "ed25519:ATWKQFSFRN": "TyTQqd6j2JlWZh97r+kTYuCbvqnPoNwO6EGovYsjY00" - }, - "signatures": { - "@bob:localhost": { - "ed25519:ATWKQFSFRN": "BQ9Gp0p+6srF+c8OyruqKKd9R4yaub3THYAyyBB/7X/rG8BwcAqFynzl1aGyFYun4Q+087a5OSiglCXI+/kQAA", - "ed25519:At1ai1VUZrCncCI7V7fEAJmBShfpqZ30xRzqcEjTjdc": "TWmDPaG7t0rZ6luauonELD3dmBDTIRryqXhgsIQRiGint2rJdic8RVyZ6a61bgu6mtBjfvU3prqMNp6sVi16Cg" - } - }, - "user_id": "@bob:localhost", - }) + device_keys_payload(&KeysQueryUser::bob_b()) } + /// A key query with a new identity (Ib) and a new device `ATWKQFSFRN`. /// `ATWKQFSFRN` is signed with the new identity but `GYKSNAWLVK` is still /// signed by the old identity (Ia). pub fn key_query_with_identity_b() -> KeyQueryResponse { - let data = json!({ - "device_keys": { - "@bob:localhost": { - "ATWKQFSFRN": Self::device_keys_payload_2_signed_by_b(), - "GYKSNAWLVK": Self::device_keys_payload_1_signed_by_a(), - } - }, - "failures": {}, - "master_keys": Self::msk_b(), - "self_signing_keys": Self::ssk_b(), - }); - ruma_response_from_json(&data) + keys_query(&KeysQueryUser::bob_b(), &[KeysQueryUser::bob_a()]) } /// A key query with no identity and a new device `OPABMDDXGX` (not /// cross-signed). pub fn key_query_with_identity_no_identity() -> KeyQueryResponse { - let data = json!({ - "device_keys": { - "@bob:localhost": { - "ATWKQFSFRN": Self::device_keys_payload_2_signed_by_b(), - "GYKSNAWLVK": Self::device_keys_payload_1_signed_by_a(), - "OPABMDDXGX": { - "algorithms": [ - "m.olm.v1.curve25519-aes-sha2", - "m.megolm.v1.aes-sha2" - ], - "device_id": "OPABMDDXGX", - "keys": { - "curve25519:OPABMDDXGX": "O6bwa9Op0E+PQPCrbTOfdYwU+j95RRPhXIHuNpe94ns", - "ed25519:OPABMDDXGX": "DvjkSNOM9XrR1gWrr2YSDvTnwnLIgKDMRr5v8HgMKak" - }, - "signatures": { - "@bob:localhost": { - "ed25519:OPABMDDXGX": "o+BBnw/SIJWxSf799Adq6jEl9X3lwCg5MJkS8GlfId+pW3ReEETK0l+9bhCAgBsNSKRtB/fmZQBhjMx4FJr+BA" - } - }, - "user_id": "@bob:localhost", - } - } - }, - "failures": {}, - }); - ruma_response_from_json(&data) + keys_query(&KeysQueryUser::bob_c(), &[KeysQueryUser::bob_a(), KeysQueryUser::bob_b()]) } } diff --git a/testing/matrix-sdk-test/src/test_json/mod.rs b/testing/matrix-sdk-test/src/test_json/mod.rs index beab57cc6..f3c677c76 100644 --- a/testing/matrix-sdk-test/src/test_json/mod.rs +++ b/testing/matrix-sdk-test/src/test_json/mod.rs @@ -10,6 +10,7 @@ use serde_json::{json, Value as JsonValue}; use crate::DEFAULT_TEST_ROOM_ID; pub mod api_responses; +pub mod keys_query; pub mod keys_query_sets; pub mod members; pub mod search_users;