fix: disallow control characters in Database names (#684)

pull/24376/head
Andrew Lamb 2021-01-21 17:55:55 -05:00 committed by GitHub
parent 0cfd543db2
commit a967e2f1dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 19 deletions

1
Cargo.lock generated
View File

@ -892,6 +892,7 @@ dependencies = [
"percent-encoding", "percent-encoding",
"serde", "serde",
"snafu", "snafu",
"test_helpers",
"tracing", "tracing",
] ]

View File

@ -20,6 +20,7 @@ percent-encoding = "2.1.0"
[dev-dependencies] [dev-dependencies]
criterion = "0.3" criterion = "0.3"
test_helpers = { path = "../test_helpers" }
[[bench]] [[bench]]
name = "benchmark" name = "benchmark"

View File

@ -18,10 +18,12 @@ pub enum DatabaseNameError {
LengthConstraint { name: String }, LengthConstraint { name: String },
#[snafu(display( #[snafu(display(
"Database name {} contains invalid characters (allowed: alphanumeric, _, -, and %)", "Database name '{}' contains invalid character. Character number {} is a control which is not allowed.", name, bad_char_offset
name
))] ))]
BadChars { name: String }, BadChars {
bad_char_offset: usize,
name: String,
},
} }
/// A correctly formed database name. /// A correctly formed database name.
@ -63,12 +65,13 @@ impl<'a> DatabaseName<'a> {
// //
// NOTE: If changing these characters, please update the error message // NOTE: If changing these characters, please update the error message
// above. // above.
if !name if let Some(bad_char_offset) = name.chars().position(|c| c.is_control()) {
.chars() return BadChars {
.all(|c| c.is_alphanumeric() || c == '_' || c == '-' || c == '%') bad_char_offset,
{ name,
return BadChars { name }.fail(); }
} .fail();
};
Ok(Self(name)) Ok(Self(name))
} }
@ -118,6 +121,7 @@ impl<'a> std::fmt::Display for DatabaseName<'a> {
mod tests { mod tests {
use super::*; use super::*;
use std::convert::TryFrom; use std::convert::TryFrom;
use test_helpers::assert_contains;
#[test] #[test]
fn test_deref() { fn test_deref() {
@ -148,8 +152,32 @@ mod tests {
} }
#[test] #[test]
fn test_bad_chars() { fn test_bad_chars_null() {
let got = DatabaseName::new("example!").unwrap_err(); let got = DatabaseName::new("example\x00").unwrap_err();
assert!(matches!(got, DatabaseNameError::BadChars { name: _n })); assert_contains!(got.to_string() , "Database name 'example\x00' contains invalid character. Character number 7 is a control which is not allowed.");
}
#[test]
fn test_bad_chars_high_control() {
let got = DatabaseName::new("\u{007f}example").unwrap_err();
assert_contains!(got.to_string() , "Database name '\u{007f}example' contains invalid character. Character number 0 is a control which is not allowed.");
}
#[test]
fn test_bad_chars_tab() {
let got = DatabaseName::new("example\tdb").unwrap_err();
assert_contains!(got.to_string() , "Database name 'example\tdb' contains invalid character. Character number 7 is a control which is not allowed.");
}
#[test]
fn test_bad_chars_newline() {
let got = DatabaseName::new("my_example\ndb").unwrap_err();
assert_contains!(got.to_string() , "Database name 'my_example\ndb' contains invalid character. Character number 10 is a control which is not allowed.");
}
#[test]
fn test_ok_chars() {
let db = DatabaseName::new("my-example-db_with_underscores and spaces").unwrap();
assert_eq!(&*db, "my-example-db_with_underscores and spaces");
} }
} }

View File

@ -615,15 +615,13 @@ mod tests {
let server = Server::new(manager, store); let server = Server::new(manager, store);
server.set_id(1); server.set_id(1);
let reject: [&str; 5] = [ let reject = vec![
"bananas!", "bananas\t",
r#""bananas\"are\"great"#, "bananas\"are\u{0099}\"great",
"bananas:good", "bananas\nfoster",
"bananas/cavendish",
"bananas\n",
]; ];
for &name in &reject { for name in reject {
let rules = DatabaseRules { let rules = DatabaseRules {
store_locally: true, store_locally: true,
..Default::default() ..Default::default()