use query_flow::{Db, LocateResult, QueryError, asset_locator};
use url::Url;
use crate::query::config::WorkspaceConfig;
use super::assets::{TextFile, TextFileContent, WorkspaceId};
use super::error::EureQueryError;
const DEFAULT_ALLOWED_HOST: &str = "eure.dev";
#[asset_locator]
pub fn text_file_locator(
db: &impl Db,
key: &TextFile,
) -> Result<LocateResult<TextFileContent>, QueryError> {
match key {
TextFile::Local(_) => {
Ok(LocateResult::Pending)
}
TextFile::Remote(url) => {
validate_url_host(db, url)?;
Ok(LocateResult::Pending)
}
}
}
fn validate_url_host(db: &impl Db, url: &Url) -> Result<(), QueryError> {
let host = url.host_str().unwrap_or("");
if host == DEFAULT_ALLOWED_HOST {
return Ok(());
}
let allowed_hosts = get_allowed_hosts_from_workspace(db)?;
if allowed_hosts
.iter()
.any(|allowed| host_matches(host, allowed))
{
return Ok(());
}
Err(EureQueryError::HostNotAllowed {
url: url.clone(),
host: host.to_string(),
}
.into())
}
fn host_matches(host: &str, pattern: &str) -> bool {
if let Some(suffix) = pattern.strip_prefix("*.") {
host == suffix || host.ends_with(&format!(".{}", suffix))
} else {
host == pattern
}
}
fn get_allowed_hosts_from_workspace(db: &impl Db) -> Result<Vec<String>, QueryError> {
let mut allowed_hosts = Vec::new();
for workspace_id in db.list_asset_keys::<WorkspaceId>() {
let config = db.query(WorkspaceConfig::new(workspace_id))?;
allowed_hosts.extend(config.config.allowed_hosts().iter().cloned());
}
Ok(allowed_hosts)
}
#[cfg(test)]
mod tests {
use super::*;
mod host_matches_tests {
use super::*;
#[test]
fn exact_match() {
assert!(host_matches("example.com", "example.com"));
assert!(!host_matches("other.com", "example.com"));
assert!(!host_matches("sub.example.com", "example.com"));
}
#[test]
fn wildcard_match_subdomain() {
assert!(host_matches("sub.example.com", "*.example.com"));
assert!(host_matches("a.b.example.com", "*.example.com"));
}
#[test]
fn wildcard_match_base() {
assert!(host_matches("example.com", "*.example.com"));
}
#[test]
fn wildcard_no_match() {
assert!(!host_matches("other.com", "*.example.com"));
assert!(!host_matches("exampleXcom", "*.example.com"));
}
#[test]
fn empty_pattern() {
assert!(!host_matches("example.com", ""));
assert!(host_matches("", ""));
}
}
}