mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Add max-age to HSTS entries
Refactors API for pushing new entries on, and adds a max age. This does not add a check for the max-age, or remove old entries from the list. Instead this just adds the data-field. servo/servo#6105
This commit is contained in:
parent
855a9487ae
commit
cb9b0c2a7a
2 changed files with 45 additions and 45 deletions
|
@ -36,6 +36,7 @@ use std::io::{BufReader, Read};
|
||||||
use std::str::{from_utf8};
|
use std::str::{from_utf8};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
use time;
|
||||||
|
|
||||||
static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None;
|
static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None;
|
||||||
static IPV4_REGEX: Regex = regex!(
|
static IPV4_REGEX: Regex = regex!(
|
||||||
|
@ -188,13 +189,24 @@ pub fn new_resource_task(user_agent: Option<String>,
|
||||||
setup_chan
|
setup_chan
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RustcDecodable, RustcEncodable)]
|
#[derive(RustcDecodable, RustcEncodable, Clone)]
|
||||||
pub struct HSTSEntry {
|
pub struct HSTSEntry {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub include_subdomains: bool
|
pub include_subdomains: bool,
|
||||||
|
pub max_age: Option<u64>,
|
||||||
|
timestamp: Option<u64>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HSTSEntry {
|
impl HSTSEntry {
|
||||||
|
pub fn new(host: String, include_subdomains: bool, max_age: Option<u64>) -> HSTSEntry {
|
||||||
|
HSTSEntry {
|
||||||
|
host: host,
|
||||||
|
include_subdomains: include_subdomains,
|
||||||
|
max_age: max_age,
|
||||||
|
timestamp: Some(time::get_time().sec as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn matches_domain(&self, host: &str) -> bool {
|
fn matches_domain(&self, host: &str) -> bool {
|
||||||
self.host == host
|
self.host == host
|
||||||
}
|
}
|
||||||
|
@ -244,30 +256,25 @@ impl HSTSList {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, host: String, include_subdomains: bool) {
|
pub fn push(&mut self, entry: HSTSEntry) {
|
||||||
if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) {
|
if IPV4_REGEX.is_match(&entry.host) || IPV6_REGEX.is_match(&entry.host) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let have_domain = self.has_domain(host.clone());
|
let have_domain = self.has_domain(entry.host.clone());
|
||||||
let have_subdomain = self.has_subdomain(host.clone());
|
let have_subdomain = self.has_subdomain(entry.host.clone());
|
||||||
|
|
||||||
if !have_domain && !have_subdomain {
|
if !have_domain && !have_subdomain {
|
||||||
self.entries.push(HSTSEntry {
|
self.entries.push(entry);
|
||||||
host: host,
|
|
||||||
include_subdomains: include_subdomains
|
|
||||||
});
|
|
||||||
} else if !have_subdomain {
|
} else if !have_subdomain {
|
||||||
self.entries = self.entries.iter().fold(Vec::new(), |mut m, e| {
|
self.entries = self.entries.iter().fold(Vec::new(), |mut m, e| {
|
||||||
let new = HSTSEntry {
|
if e.matches_domain(&entry.host) {
|
||||||
host: host.clone(),
|
// Update the entry if there's an exact domain match.
|
||||||
include_subdomains: include_subdomains
|
m.push(entry.clone());
|
||||||
};
|
|
||||||
|
|
||||||
if e.matches_domain(&host) {
|
|
||||||
m.push(new);
|
|
||||||
} else {
|
} else {
|
||||||
m.push(new);
|
// Ignore the new details if it's a subdomain match, or not
|
||||||
|
// a match at all. Just use the existing entry
|
||||||
|
m.push(e.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
m
|
m
|
||||||
|
|
|
@ -25,7 +25,9 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv6_addresses() {
|
||||||
entries: Vec::new()
|
entries: Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
list.push("2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false);
|
list.push(HSTSEntry::new(
|
||||||
|
"2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false, None
|
||||||
|
));
|
||||||
|
|
||||||
assert!(list.entries.len() == 0)
|
assert!(list.entries.len() == 0)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +38,7 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() {
|
||||||
entries: Vec::new()
|
entries: Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
list.push("8.8.8.8".to_string(), false);
|
list.push(HSTSEntry::new("8.8.8.8".to_string(), false, None));
|
||||||
|
|
||||||
assert!(list.entries.len() == 0)
|
assert!(list.entries.len() == 0)
|
||||||
}
|
}
|
||||||
|
@ -44,13 +46,10 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() {
|
fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() {
|
||||||
let mut list = HSTSList {
|
let mut list = HSTSList {
|
||||||
entries: vec!(HSTSEntry {
|
entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None))
|
||||||
host: "mozilla.org".to_string(),
|
|
||||||
include_subdomains: true
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
list.push("servo.mozilla.org".to_string(), false);
|
list.push(HSTSEntry::new("servo.mozilla.org".to_string(), false, None));
|
||||||
|
|
||||||
assert!(list.entries.len() == 1)
|
assert!(list.entries.len() == 1)
|
||||||
}
|
}
|
||||||
|
@ -58,15 +57,12 @@ fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_a
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() {
|
fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() {
|
||||||
let mut list = HSTSList {
|
let mut list = HSTSList {
|
||||||
entries: vec!(HSTSEntry {
|
entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None))
|
||||||
host: "mozilla.org".to_string(),
|
|
||||||
include_subdomains: true
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(list.always_secure("servo.mozilla.org"));
|
assert!(list.always_secure("servo.mozilla.org"));
|
||||||
|
|
||||||
list.push("mozilla.org".to_string(), false);
|
list.push(HSTSEntry::new("mozilla.org".to_string(), false, None));
|
||||||
|
|
||||||
assert!(!list.always_secure("servo.mozilla.org"))
|
assert!(!list.always_secure("servo.mozilla.org"))
|
||||||
}
|
}
|
||||||
|
@ -74,13 +70,10 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() {
|
fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() {
|
||||||
let mut list = HSTSList {
|
let mut list = HSTSList {
|
||||||
entries: vec!(HSTSEntry {
|
entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, None))
|
||||||
host: "mozilla.org".to_string(),
|
|
||||||
include_subdomains: false
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
list.push("mozilla.org".to_string(), false);
|
list.push(HSTSEntry::new("mozilla.org".to_string(), false, None));
|
||||||
|
|
||||||
assert!(list.entries.len() == 1)
|
assert!(list.entries.len() == 1)
|
||||||
}
|
}
|
||||||
|
@ -93,7 +86,7 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() {
|
||||||
|
|
||||||
assert!(!list.always_secure("mozilla.org"));
|
assert!(!list.always_secure("mozilla.org"));
|
||||||
|
|
||||||
list.push("mozilla.org".to_string(), true);
|
list.push(HSTSEntry::new("mozilla.org".to_string(), true, None));
|
||||||
|
|
||||||
assert!(list.always_secure("mozilla.org"));
|
assert!(list.always_secure("mozilla.org"));
|
||||||
}
|
}
|
||||||
|
@ -143,7 +136,7 @@ fn test_hsts_list_with_no_entries_does_not_always_secure() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hsts_list_with_exact_domain_entry_is_always_secure() {
|
fn test_hsts_list_with_exact_domain_entry_is_always_secure() {
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)]
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(hsts_list.always_secure("mozilla.org") == true);
|
assert!(hsts_list.always_secure("mozilla.org") == true);
|
||||||
|
@ -152,7 +145,7 @@ fn test_hsts_list_with_exact_domain_entry_is_always_secure() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() {
|
fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() {
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)]
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(hsts_list.always_secure("servo.mozilla.org") == true);
|
assert!(hsts_list.always_secure("servo.mozilla.org") == true);
|
||||||
|
@ -161,7 +154,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secur
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() {
|
fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() {
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)]
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(hsts_list.always_secure("servo.mozilla.org") == false);
|
assert!(hsts_list.always_secure("servo.mozilla.org") == false);
|
||||||
|
@ -170,7 +163,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() {
|
fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() {
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)]
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(hsts_list.always_secure("servo-mozilla.org") == false);
|
assert!(hsts_list.always_secure("servo-mozilla.org") == false);
|
||||||
|
@ -179,7 +172,7 @@ fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secu
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() {
|
fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() {
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)]
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(hsts_list.always_secure("mozilla.org") == true);
|
assert!(hsts_list.always_secure("mozilla.org") == true);
|
||||||
|
@ -189,7 +182,7 @@ fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() {
|
||||||
fn test_make_hsts_secure_does_not_change_explicit_port() {
|
fn test_make_hsts_secure_does_not_change_explicit_port() {
|
||||||
let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None);
|
let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None);
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)]
|
||||||
};
|
};
|
||||||
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
||||||
|
|
||||||
|
@ -200,7 +193,7 @@ fn test_make_hsts_secure_does_not_change_explicit_port() {
|
||||||
fn test_make_hsts_secure_doesnt_affect_non_http_schemas() {
|
fn test_make_hsts_secure_doesnt_affect_non_http_schemas() {
|
||||||
let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None);
|
let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None);
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)]
|
||||||
};
|
};
|
||||||
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
||||||
|
|
||||||
|
@ -211,7 +204,7 @@ fn test_make_hsts_secure_doesnt_affect_non_http_schemas() {
|
||||||
fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() {
|
fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() {
|
||||||
let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None);
|
let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None);
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)]
|
||||||
};
|
};
|
||||||
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
||||||
|
|
||||||
|
@ -222,7 +215,7 @@ fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomain
|
||||||
fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() {
|
fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() {
|
||||||
let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None);
|
let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None);
|
||||||
let hsts_list = HSTSList {
|
let hsts_list = HSTSList {
|
||||||
entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}]
|
entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)]
|
||||||
};
|
};
|
||||||
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
let secure_load_data = hsts_list.make_hsts_secure(load_data);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue