Skip to content

Commit abe35a7

Browse files
committed
Merge remote-tracking branch 'upstream/pr/816'
2 parents b5199e7 + e2bfdaa commit abe35a7

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/krate.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ use util::{RequestUtils, CargoResult, internal, ChainError, human};
4040
use version::{EncodableVersion, NewVersion};
4141
use {Model, User, Keyword, Version, Category, Badge, Replica};
4242

43+
/// Hosts in this blacklist are known to not be hosting documentation,
44+
/// and are possibly of malicious intent e.g. ad tracking networks, etc.
45+
const DOCUMENTATION_BLACKLIST: [&'static str; 1] = ["rust-ci.org"];
46+
4347
#[derive(Debug, Insertable, Queryable, Identifiable, Associations, AsChangeset)]
4448
#[belongs_to(Crate)]
4549
#[primary_key(crate_id, date)]
@@ -538,6 +542,8 @@ impl Crate {
538542
let keyword_ids = keywords.map(|kws| kws.iter().map(|kw| kw.keyword.clone()).collect());
539543
let category_ids = categories.map(|cats| cats.iter().map(|cat| cat.slug.clone()).collect());
540544
let badges = badges.map(|bs| bs.into_iter().map(|b| b.encodable()).collect());
545+
let documentation = Crate::remove_blacklisted_documentation_urls(documentation);
546+
541547
EncodableCrate {
542548
id: name.clone(),
543549
name: name.clone(),
@@ -566,6 +572,34 @@ impl Crate {
566572
}
567573
}
568574

575+
/// Return `None` if the documentation URL host matches a blacklisted host
576+
fn remove_blacklisted_documentation_urls(url: Option<String>) -> Option<String> {
577+
// Handles if documentation URL is None
578+
let url = match url {
579+
Some(url) => url,
580+
None => return None,
581+
};
582+
583+
// Handles unsuccessful parsing of documentation URL
584+
let parsed_url = match Url::parse(&url) {
585+
Ok(parsed_url) => parsed_url,
586+
Err(_) => return None,
587+
};
588+
589+
// Extract host string from documentation URL
590+
let url_host = match parsed_url.host_str() {
591+
Some(url_host) => url_host,
592+
None => return None,
593+
};
594+
595+
// Match documentation URL host against blacklisted host array elements
596+
if DOCUMENTATION_BLACKLIST.contains(&url_host) {
597+
None
598+
} else {
599+
Some(url)
600+
}
601+
}
602+
569603
pub fn max_version(&self, conn: &PgConnection) -> CargoResult<semver::Version> {
570604
use schema::versions::dsl::*;
571605

@@ -1594,3 +1628,41 @@ pub fn reverse_dependencies(req: &mut Request) -> CargoResult<Response> {
15941628
use diesel::types::{Text, Date};
15951629
sql_function!(canon_crate_name, canon_crate_name_t, (x: Text) -> Text);
15961630
sql_function!(to_char, to_char_t, (a: Date, b: Text) -> Text);
1631+
1632+
#[cfg(test)]
1633+
mod tests {
1634+
use super::Crate;
1635+
1636+
#[test]
1637+
fn documentation_blacklist_no_url_provided() {
1638+
assert_eq!(Crate::remove_blacklisted_documentation_urls(None), None);
1639+
}
1640+
1641+
#[test]
1642+
fn documentation_blacklist_invalid_url() {
1643+
assert_eq!(
1644+
Crate::remove_blacklisted_documentation_urls(Some(String::from("not a url"))),
1645+
None
1646+
);
1647+
}
1648+
1649+
#[test]
1650+
fn documentation_blacklist_url_contains_partial_match() {
1651+
assert_eq!(
1652+
Crate::remove_blacklisted_documentation_urls(
1653+
Some(String::from("http://rust-ci.organists.com")),
1654+
),
1655+
Some(String::from("http://rust-ci.organists.com"))
1656+
);
1657+
}
1658+
1659+
#[test]
1660+
fn documentation_blacklist_blacklisted_url() {
1661+
assert_eq!(
1662+
Crate::remove_blacklisted_documentation_urls(Some(String::from(
1663+
"http://rust-ci.org/crate/crate-0.1/doc/crate-0.1",
1664+
))),
1665+
None
1666+
);
1667+
}
1668+
}

src/tests/krate.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,3 +2094,24 @@ fn test_default_sort_recent() {
20942094
assert_eq!(json.crates[1].recent_downloads, Some(0));
20952095
assert_eq!(json.crates[1].downloads, 20);
20962096
}
2097+
2098+
#[test]
2099+
fn block_blacklisted_documentation_url() {
2100+
let (_b, app, middle) = ::app();
2101+
2102+
let _ = {
2103+
let conn = app.diesel_database.get().unwrap();
2104+
let u = ::new_user("foo").create_or_update(&conn).unwrap();
2105+
::CrateBuilder::new("foo_bad_doc_url", u.id)
2106+
.documentation(
2107+
"http://rust-ci.org/foo/foo_bad_doc_url/doc/foo_bad_doc_url/",
2108+
)
2109+
.expect_build(&conn)
2110+
};
2111+
2112+
let mut req = ::req(app, Method::Get, "/api/v1/crates/foo_bad_doc_url");
2113+
let mut response = ok_resp!(middle.call(&mut req));
2114+
let json: CrateResponse = ::json(&mut response);
2115+
2116+
assert_eq!(json.krate.documentation, None);
2117+
}

0 commit comments

Comments
 (0)