Skip to main content

tuwunel_api/client/keys/
upload_signatures.rs

1use std::{collections::BTreeMap, fmt};
2
3use axum::extract::State;
4use ruma::{
5	OwnedUserId, UserId,
6	api::client::keys::upload_signatures::v3::{Failure, FailureErrorCode, Request, Response},
7};
8use serde::{
9	Deserialize, Deserializer,
10	de::{DeserializeSeed, IgnoredAny, MapAccess, Visitor},
11};
12use serde_json::{error::Category, json, value::RawValue};
13use tuwunel_core::{
14	Error, Result, debug, err,
15	smallvec::SmallVec,
16	utils::{IterStream, ReadyExt, stream::BroadbandExt},
17	warn,
18};
19use tuwunel_service::Services;
20
21use crate::Ruma;
22
23type Failures = BTreeMap<OwnedUserId, BTreeMap<String, Failure>>;
24type Rejected = (FailureErrorCode, String);
25type Signatures = SmallVec<[(String, String); 1]>;
26
27struct ObjectField<'a>(&'a str);
28
29struct ObjectFieldVisitor<'a>(&'a str);
30
31struct SignaturePairs(Signatures);
32
33struct SignaturePairsVisitor;
34
35/// Uploads end-to-end key signatures from the sender user.
36///
37/// `POST /_matrix/client/r0/keys/signatures/upload`
38pub(crate) async fn upload_signatures_route(
39	State(services): State<crate::State>,
40	body: Ruma<Request>,
41) -> Result<Response> {
42	let sender_user = body.sender_user();
43
44	if body.signed_keys.is_empty() {
45		debug!("Empty signed_keys sent in key signature upload");
46		return Ok(Response::new());
47	}
48
49	let failures = body
50		.signed_keys
51		.iter()
52		.flat_map(|(user_id, keys)| {
53			keys.iter()
54				.map(move |(key_id, key)| (user_id.as_ref(), key_id, key))
55		})
56		.stream()
57		.broad_filter_map(async |(user_id, key_id, key)| {
58			sign_key(&services, sender_user, user_id, key_id, key)
59				.await
60				.err()
61				.map(|rejected| (user_id, key_id, rejected))
62		})
63		.ready_fold(
64			Ok(Failures::new()),
65			|failures: Result<Failures>, (user_id, key_id, rejected)| {
66				let mut failures = failures?;
67				let failure = failure(rejected)?;
68
69				failures
70					.entry(user_id.to_owned())
71					.or_default()
72					.insert(key_id.to_owned(), failure);
73
74				Ok(failures)
75			},
76		)
77		.await?;
78
79	Ok(Response { failures })
80}
81
82async fn sign_key(
83	services: &Services,
84	sender_user: &UserId,
85	user_id: &UserId,
86	key_id: &str,
87	key: &RawValue,
88) -> Result<(), Rejected> {
89	let signatures = signatures_from_key(sender_user, key)
90		.map_err(|error| (FailureErrorCode::InvalidSignature, error))?;
91
92	services
93		.users
94		.sign_key(user_id, key_id, signatures, sender_user)
95		.await
96		.map_err(|error| match error {
97			| Error::Signatures(_) => (
98				FailureErrorCode::InvalidSignature,
99				"Signature does not verify against the stored key.".to_owned(),
100			),
101			| error => {
102				if !matches!(&error, Error::Request(..)) {
103					warn!(?error, "Failed to upload key signature");
104				}
105
106				(FailureErrorCode::from(error.kind().to_string()), error.sanitized_message())
107			},
108		})
109}
110
111fn signatures_from_key(sender_user: &UserId, key: &RawValue) -> Result<Signatures, String> {
112	let signatures = object_field(key.get(), "signatures")
113		.map_err(|error| {
114			if matches!(error.classify(), Category::Data) {
115				String::from("The signed key must be an object.")
116			} else {
117				format!("Invalid signed key JSON: {error}")
118			}
119		})?
120		.ok_or_else(|| String::from("No signature from the uploading user."))?;
121
122	let signatures = object_field(signatures.get(), sender_user.as_str())
123		.map_err(|_| String::from("The signatures field must be an object."))?
124		.ok_or_else(|| String::from("No signature from the uploading user."))?;
125
126	if !signatures.get().trim_start().starts_with('{') {
127		return Err(String::from("Signatures from the uploading user must be an object."));
128	}
129
130	let SignaturePairs(signatures) = serde_json::from_str(signatures.get())
131		.map_err(|_| String::from("Signature values must be strings."))?;
132
133	(!signatures.is_empty())
134		.then_some(signatures)
135		.ok_or_else(|| String::from("No signature from the uploading user."))
136}
137
138fn failure((errcode, error): Rejected) -> Result<Failure> {
139	serde_json::from_value(json!({ "errcode": errcode, "error": error }))
140		.map_err(|error| err!(SerdeDe("Failed to encode signature upload failure: {error}")))
141}
142
143fn object_field<'de>(json: &'de str, field: &str) -> serde_json::Result<Option<&'de RawValue>> {
144	let mut deserializer = serde_json::Deserializer::from_str(json);
145	let value = ObjectField(field).deserialize(&mut deserializer)?;
146
147	deserializer.end()?;
148	Ok(value)
149}
150
151impl<'de> DeserializeSeed<'de> for ObjectField<'_> {
152	type Value = Option<&'de RawValue>;
153
154	fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
155	where
156		D: Deserializer<'de>,
157	{
158		deserializer.deserialize_map(ObjectFieldVisitor(self.0))
159	}
160}
161
162impl<'de> Visitor<'de> for ObjectFieldVisitor<'_> {
163	type Value = Option<&'de RawValue>;
164
165	fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
166		formatter.write_str("a JSON object")
167	}
168
169	fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
170	where
171		A: MapAccess<'de>,
172	{
173		let mut value = None;
174
175		while let Some(name) = map.next_key::<String>()? {
176			if name == self.0 {
177				value = Some(map.next_value()?);
178			} else {
179				map.next_value::<IgnoredAny>()?;
180			}
181		}
182
183		Ok(value)
184	}
185}
186
187impl<'de> Deserialize<'de> for SignaturePairs {
188	fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
189	where
190		D: Deserializer<'de>,
191	{
192		deserializer.deserialize_map(SignaturePairsVisitor)
193	}
194}
195
196impl<'de> Visitor<'de> for SignaturePairsVisitor {
197	type Value = SignaturePairs;
198
199	fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
200		formatter.write_str("an object containing string signatures")
201	}
202
203	fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
204	where
205		A: MapAccess<'de>,
206	{
207		let mut signatures = Signatures::new();
208
209		while let Some((key_id, signature)) = map.next_entry::<String, String>()? {
210			if let Some(index) = signatures
211				.iter()
212				.position(|(existing, _)| existing == &key_id)
213			{
214				signatures[index].1 = signature;
215			} else {
216				signatures.push((key_id, signature));
217			}
218		}
219
220		Ok(SignaturePairs(signatures))
221	}
222}
223
224#[cfg(test)]
225mod tests {
226	use ruma::user_id;
227	use serde_json::value::to_raw_value;
228
229	use super::*;
230
231	#[test]
232	fn extracts_only_uploading_users_signatures() {
233		let sender_user = user_id!("@alice:example.com");
234		let key = to_raw_value(&json!({
235			"signatures": {
236				"@alice:example.com": { "ed25519:ALICE": "alice-signature" },
237				"@bob:example.com": { "ed25519:BOB": "bob-signature" },
238			},
239		}))
240		.expect("signed key should serialize");
241
242		let signatures = signatures_from_key(sender_user, &key)
243			.expect("the uploading user's signature should be extracted");
244
245		assert_eq!(signatures.as_slice(), &[(
246			"ed25519:ALICE".to_owned(),
247			"alice-signature".to_owned()
248		)]);
249	}
250
251	#[test]
252	fn rejects_empty_uploading_user_signatures() {
253		let sender_user = user_id!("@alice:example.com");
254		let key = to_raw_value(&json!({ "signatures": { "@alice:example.com": {} } }))
255			.expect("signed key should serialize");
256
257		let error = signatures_from_key(sender_user, &key)
258			.expect_err("an empty signature map should be rejected");
259
260		assert_eq!(error, "No signature from the uploading user.");
261	}
262
263	#[test]
264	fn rejects_missing_uploading_user_signatures() {
265		let sender_user = user_id!("@alice:example.com");
266		let key = to_raw_value(&json!({ "user_id": "@alice:example.com" }))
267			.expect("signed key should serialize");
268
269		let error = signatures_from_key(sender_user, &key)
270			.expect_err("a missing signature map should be rejected");
271
272		assert_eq!(error, "No signature from the uploading user.");
273	}
274
275	#[test]
276	fn rejects_non_object_signed_key() {
277		let sender_user = user_id!("@alice:example.com");
278		let key = to_raw_value(&json!([])).expect("signed key should serialize");
279
280		let error = signatures_from_key(sender_user, &key)
281			.expect_err("a non-object signed key should be rejected");
282
283		assert_eq!(error, "The signed key must be an object.");
284	}
285
286	#[test]
287	fn rejects_non_string_signature() {
288		let sender_user = user_id!("@alice:example.com");
289		let key = to_raw_value(&json!({
290			"signatures": { "@alice:example.com": { "ed25519:ALICE": 7 } },
291		}))
292		.expect("signed key should serialize");
293
294		let error = signatures_from_key(sender_user, &key)
295			.expect_err("a non-string signature should be rejected");
296
297		assert_eq!(error, "Signature values must be strings.");
298	}
299
300	#[test]
301	fn serializes_typed_failure() {
302		let failure = failure((
303			FailureErrorCode::InvalidSignature,
304			"Signature does not verify.".to_owned(),
305		))
306		.expect("failure should deserialize");
307
308		let failure = serde_json::to_value(failure).expect("failure should serialize");
309
310		assert_eq!(failure["errcode"], "M_INVALID_SIGNATURE");
311		assert_eq!(failure["error"], "Signature does not verify.");
312	}
313}