Skip to content

Commit

Permalink
refactor(web-security)!: use dedicated table for content security pol…
Browse files Browse the repository at this point in the history
…icies
  • Loading branch information
azasypkin committed Nov 23, 2023
1 parent 83f48c0 commit 19ddea8
Show file tree
Hide file tree
Showing 39 changed files with 3,103 additions and 2,062 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions migrations/20231120203804_web_security.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Create table to store content security policies
CREATE TABLE IF NOT EXISTS user_data_web_security_csp
(
id BLOB PRIMARY KEY,
name TEXT NOT NULL COLLATE NOCASE,
directives BLOB NOT NULL,
created_at INTEGER NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
UNIQUE (name, user_id)
) STRICT;
36 changes: 29 additions & 7 deletions src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub use self::{
email_transport::{EmailTransport, EmailTransportError},
ip_addr_ext::IpAddrExt,
};
use url::Url;
use std::net::IpAddr;
use url::{Host, Url};

/// Network utilities.
#[derive(Clone)]
Expand All @@ -32,16 +33,17 @@ impl<DR: DnsResolver, ET: EmailTransport> Network<DR, ET> {
}

// Checks if the specific hostname is a domain and public (not pointing to the local network).
if let Some(domain) = url.domain() {
match self.resolver.lookup_ip(domain).await {
match url.host() {
Some(Host::Domain(domain)) => match self.resolver.lookup_ip(domain).await {
Ok(lookup) => lookup.iter().all(|ip| IpAddrExt::is_global(&ip)),
Err(err) => {
log::error!("Cannot resolve domain ({domain}) to IP: {err}");
false
}
}
} else {
false
},
Some(Host::Ipv4(ip)) => IpAddrExt::is_global(&IpAddr::V4(ip)),
Some(Host::Ipv6(ip)) => IpAddrExt::is_global(&IpAddr::V6(ip)),
None => false,
}
}
}
Expand All @@ -60,7 +62,7 @@ pub mod tests {

pub use super::dns_resolver::tests::*;

#[actix_rt::test]
#[tokio::test]
async fn correctly_checks_public_web_urls() -> anyhow::Result<()> {
let public_network = Network::new(
MockResolver::new_with_records::<1>(vec![Record::from_rdata(
Expand Down Expand Up @@ -107,4 +109,24 @@ pub mod tests {

Ok(())
}

#[tokio::test]
async fn correctly_checks_public_ips() -> anyhow::Result<()> {
let network = Network::new(MockResolver::new(), AsyncStubTransport::new_ok());
for (ip, is_supported) in [
("127.0.0.1", false),
("10.254.0.0", false),
("192.168.10.65", false),
("172.16.10.65", false),
("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", false),
("[::1]", false),
("217.88.39.143", true),
("[2001:1234:abcd:5678:0221:2fff:feb5:6e10]", true),
] {
let url = Url::parse(&format!("http://{}/my-page", ip))?;
assert_eq!(network.is_public_web_url(&url).await, is_supported);
}

Ok(())
}
}
5 changes: 3 additions & 2 deletions src/server/extractors/user_share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ mod tests {
use actix_web::{test::TestRequest, FromRequest};
use insta::assert_debug_snapshot;
use time::OffsetDateTime;
use uuid::uuid;

#[actix_rt::test]
async fn fails_if_header_is_not_provided() -> anyhow::Result<()> {
Expand Down Expand Up @@ -104,7 +105,7 @@ mod tests {
id: UserShareId::new(),
user_id: user.id,
resource: SharedResource::ContentSecurityPolicy {
policy_name: "my-policy".to_string(),
policy_id: uuid!("00000000-0000-0000-0000-000000000000"),
},
created_at: OffsetDateTime::now_utc(),
};
Expand Down Expand Up @@ -135,7 +136,7 @@ mod tests {
id: UserShareId::new(),
user_id: user.id,
resource: SharedResource::ContentSecurityPolicy {
policy_name: "my-policy".to_string(),
policy_id: uuid!("00000000-0000-0000-0000-000000000000"),
},
created_at: OffsetDateTime::from_unix_timestamp(946720800)?,
};
Expand Down
Loading

0 comments on commit 19ddea8

Please sign in to comment.