signatures: Rewrite redaction to be more efficient
This commit is contained in:
parent
414161f0fd
commit
fa58f09a23
@ -1,6 +1,6 @@
|
|||||||
//! Functions for signing and verifying JSON and events.
|
//! Functions for signing and verifying JSON and events.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{cmp, collections::HashMap, mem};
|
||||||
|
|
||||||
use base64::{decode_config, encode_config, STANDARD_NO_PAD};
|
use base64::{decode_config, encode_config, STANDARD_NO_PAD};
|
||||||
use ring::digest::{digest, SHA256};
|
use ring::digest::{digest, SHA256};
|
||||||
@ -33,9 +33,12 @@ static ALLOWED_KEYS: &[&str] = &[
|
|||||||
"membership",
|
"membership",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The fields of an *m.room.power_levels* event's `content` key that are allowed to remain in an
|
fn allowed_content_keys_for(event_type: &str) -> &'static [&'static str] {
|
||||||
/// event during redaction.
|
match event_type {
|
||||||
static ALLOWED_POWER_LEVELS_KEYS: &[&str] = &[
|
"m.room.member" => &["membership"],
|
||||||
|
"m.room.create" => &["creator"],
|
||||||
|
"m.room.join_rules" => &["join_rule"],
|
||||||
|
"m.room.power_levels" => &[
|
||||||
"ban",
|
"ban",
|
||||||
"events",
|
"events",
|
||||||
"events_default",
|
"events_default",
|
||||||
@ -44,7 +47,11 @@ static ALLOWED_POWER_LEVELS_KEYS: &[&str] = &[
|
|||||||
"state_default",
|
"state_default",
|
||||||
"users",
|
"users",
|
||||||
"users_default",
|
"users_default",
|
||||||
];
|
],
|
||||||
|
"m.room.history_visibility" => &["history_visibility"],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The fields to remove from a JSON object when converting JSON into the "canonical" form.
|
/// The fields to remove from a JSON object when converting JSON into the "canonical" form.
|
||||||
static CANONICAL_JSON_FIELDS_TO_REMOVE: &[&str] = &["signatures", "unsigned"];
|
static CANONICAL_JSON_FIELDS_TO_REMOVE: &[&str] = &["signatures", "unsigned"];
|
||||||
@ -701,59 +708,33 @@ pub fn redact(value: &Value) -> Result<Value, Error> {
|
|||||||
None => return Err(Error::new("field `type` in JSON value must be present")),
|
None => return Err(Error::new("field `type` in JSON value must be present")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let event_type = match event_type_value.as_str() {
|
let allowed_content_keys = match event_type_value.as_str() {
|
||||||
Some(event_type) => event_type.to_string(),
|
Some(event_type) => allowed_content_keys_for(event_type),
|
||||||
None => return Err(Error::new("field `type` in JSON value must be a JSON string")),
|
None => return Err(Error::new("field `type` in JSON value must be a JSON string")),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(content_value) = event.get_mut("content") {
|
if let Some(content_value) = event.get_mut("content") {
|
||||||
let map = match content_value {
|
let content = match content_value {
|
||||||
Value::Object(ref mut map) => map,
|
Value::Object(ref mut map) => map,
|
||||||
_ => return Err(Error::new("field `content` in JSON value must be a JSON object")),
|
_ => return Err(Error::new("field `content` in JSON value must be a JSON object")),
|
||||||
};
|
};
|
||||||
|
|
||||||
for key in map.clone().keys() {
|
let max_values = cmp::max(content.len(), allowed_content_keys.len());
|
||||||
match event_type.as_ref() {
|
let mut old_content = mem::replace(content, serde_json::Map::with_capacity(max_values));
|
||||||
"m.room.member" => {
|
|
||||||
if key != "membership" {
|
for &key in allowed_content_keys {
|
||||||
map.remove(key);
|
if let Some(value) = old_content.remove(key) {
|
||||||
|
content.insert(key.to_owned(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"m.room.create" => {
|
|
||||||
if key != "creator" {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"m.room.join_rules" => {
|
|
||||||
if key != "join_rules" {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"m.room.power_levels" => {
|
|
||||||
if !ALLOWED_POWER_LEVELS_KEYS.contains(&key.as_ref()) {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"m.room.aliases" => {
|
|
||||||
if key != "aliases" {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"m.room.history_visibility" => {
|
|
||||||
if key != "history_visibility" {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in event.clone().keys() {
|
let max_values = cmp::max(event.len(), ALLOWED_KEYS.len());
|
||||||
if !ALLOWED_KEYS.contains(&key.as_ref()) {
|
let mut old_event = mem::replace(event, serde_json::Map::with_capacity(max_values));
|
||||||
event.remove(key);
|
|
||||||
|
for &key in ALLOWED_KEYS {
|
||||||
|
if let Some(value) = old_event.remove(key) {
|
||||||
|
event.insert(key.to_owned(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user