perimeterx-fastly-enforcer 2.2.2

PerimeterX Fastly Compute@Edge Rust Enforcer
Documentation
use std::collections::HashSet;

use crate::modules::pxconstants::WHITELIST_EXT;
use crate::pxconfig::*;
use crate::pxcontext::PXModuleMode;
use regex::Regex;

#[test]
fn strip_json_quotes_removes_surrounding_quotes() {
    assert_eq!(strip_json_quotes(r#""active_blocking""#), "active_blocking");
    assert_eq!(strip_json_quotes(r#""monitor""#), "monitor");
    assert_eq!(strip_json_quotes(r#""hello""#), "hello");
}

#[test]
fn strip_json_quotes_leaves_unquoted_strings() {
    assert_eq!(strip_json_quotes("active_blocking"), "active_blocking");
    assert_eq!(strip_json_quotes("monitor"), "monitor");
    assert_eq!(strip_json_quotes(""), "");
}

#[test]
fn strip_json_quotes_ignores_partial_quotes() {
    assert_eq!(strip_json_quotes(r#""only_start"#), r#""only_start"#);
    assert_eq!(strip_json_quotes(r#"only_end""#), r#"only_end""#);
}

#[test]
fn set_from_raw_parses_quoted_module_mode() {
    let mut conf = PXConfig::default();
    assert_eq!(conf.module_mode, PXModuleMode::Monitor);

    conf.set_from_raw(PXConfigKey::ModuleMode, r#""active_blocking""#);
    assert_eq!(conf.module_mode, PXModuleMode::Blocking);
}

#[test]
fn set_from_raw_parses_unquoted_module_mode() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::ModuleMode, "active_blocking");
    assert_eq!(conf.module_mode, PXModuleMode::Blocking);
}

#[test]
fn default_filter_by_extension_uses_whitelist_ext() {
    let conf = PXConfig::default();
    let expected: Vec<String> = WHITELIST_EXT.iter().map(|ext| (*ext).to_owned()).collect();
    assert_eq!(conf.filter_by_extension, expected);
}

#[test]
fn parse_vec_csv_input() {
    assert_eq!(parse_vec("a, b, c"), vec!["a", "b", "c"]);
    assert_eq!(parse_vec("a,,b"), vec!["a", "b"]);
    assert_eq!(parse_vec("a, , b"), vec!["a", "b"]);
    assert_eq!(parse_vec(" , , "), Vec::<String>::new());
    assert_eq!(parse_vec(""), Vec::<String>::new());
}

#[test]
fn parse_vec_json_array_input() {
    assert_eq!(parse_vec(r#"["a","b","c"]"#), vec!["a", "b", "c"]);
    assert_eq!(parse_vec(r#"["/api","/health"]"#), vec!["/api", "/health"]);
}

#[test]
fn parse_vec_empty_json_array() {
    assert_eq!(parse_vec("[]"), Vec::<String>::new());
}

#[test]
fn parse_vec_json_array_filters_empty_strings() {
    assert_eq!(parse_vec(r#"["a","","b"]"#), vec!["a", "b"]);
    assert_eq!(parse_vec(r#"["",""]"#), Vec::<String>::new());
}

#[test]
#[cfg(feature = "kv_store")]
fn json_value_to_raw_store_strings() {
    let v = serde_json::json!("active_blocking");
    assert_eq!(json_value_to_raw_store(&v), "active_blocking");
}

#[test]
#[cfg(feature = "kv_store")]
fn json_value_to_raw_store_arrays() {
    let v = serde_json::json!(["/api", "/health"]);
    assert_eq!(json_value_to_raw_store(&v), "/api,/health");

    let empty = serde_json::json!([]);
    assert_eq!(json_value_to_raw_store(&empty), "");
}

#[test]
#[cfg(feature = "kv_store")]
fn json_value_to_raw_store_ci_endpoint_objects() {
    let v = serde_json::json!([{
        "method": "post",
        "path": "/login",
        "sent_through": "body",
        "user_field": "username",
        "pass_field": "password"
    }]);
    let stored = json_value_to_raw_store(&v);
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::LoginCredentialsExtraction, &stored);
    assert_eq!(conf.login_credentials_extraction.len(), 1);
    assert_eq!(conf.prepared_ci_endpoints.len(), 1);
    assert_eq!(
        conf.login_credentials_extraction
            .first()
            .map(|e| e.path.as_str()),
        Some("/login")
    );
}

#[test]
fn set_from_raw_ci_endpoint_empty_object_resets_endpoints() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(
        PXConfigKey::LoginCredentialsExtraction,
        r#"[{
        "method": "post",
        "path": "/login",
        "sent_through": "body",
        "user_field": "username",
        "pass_field": "password"
    }]"#,
    );
    assert_eq!(conf.login_credentials_extraction.len(), 1);
    assert_eq!(conf.prepared_ci_endpoints.len(), 1);

    conf.set_from_raw(PXConfigKey::LoginCredentialsExtraction, "[{}]");
    assert!(conf.login_credentials_extraction.is_empty());
    assert!(conf.prepared_ci_endpoints.is_empty());
}

#[test]
fn set_from_value_ci_endpoint_empty_object_resets_endpoints() {
    let mut conf = PXConfig {
        login_credentials_extraction: vec![PXCredentialEndpointConfig {
            path: "/login".to_owned(),
            method: "post".to_owned(),
            ..Default::default()
        }],
        ..Default::default()
    };
    rebuild_prepared_ci_endpoints(&mut conf);
    assert_eq!(conf.prepared_ci_endpoints.len(), 1);

    let set_result = conf.set_from_value(
        PXConfigKey::LoginCredentialsExtraction,
        &serde_json::json!({}),
    );
    assert!(set_result.is_ok());
    assert!(conf.login_credentials_extraction.is_empty());
    assert!(conf.prepared_ci_endpoints.is_empty());
}

#[test]
fn set_from_raw_vec_excludes_empty_strings() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::EnforcedRoutes, "");
    assert!(conf.enforced_routes.is_empty());

    conf.set_from_raw(PXConfigKey::EnforcedRoutes, " , , ");
    assert!(conf.enforced_routes.is_empty());

    conf.set_from_raw(PXConfigKey::EnforcedRoutes, "/api, , /health");
    assert_eq!(conf.enforced_routes, vec!["/api", "/health"]);
}

#[test]
fn set_from_raw_vec_handles_json_array() {
    let mut conf = PXConfig::default();

    conf.set_from_raw(PXConfigKey::EnforcedRoutes, "[]");
    assert!(conf.enforced_routes.is_empty());

    conf.set_from_raw(PXConfigKey::EnforcedRoutes, r#"["/api","/health"]"#);
    assert_eq!(conf.enforced_routes, vec!["/api", "/health"]);
}

#[test]
fn set_from_raw_graphql_keywords_parses_patterns() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::GraphqlKeywords, r#"["user","friends?","id"]"#);
    let pats: Vec<&str> = conf.graphql_keywords.iter().map(Regex::as_str).collect();
    assert_eq!(pats, vec!["user", "friends?", "id"]);
}

#[test]
fn graphql_keywords_set_from_value() {
    let mut conf = PXConfig::default();
    let v = serde_json::json!(["user", "friends?", "id"]);
    let set_result = conf.set_from_value(PXConfigKey::GraphqlKeywords, &v);
    assert!(set_result.is_ok());
    let pats: Vec<&str> = conf.graphql_keywords.iter().map(Regex::as_str).collect();
    assert_eq!(pats, vec!["user", "friends?", "id"]);
}

#[test]
fn secret_store_keys_contains_only_expected_fields() {
    let keys: HashSet<PXConfigKey> = secret_store_keys().iter().copied().collect();
    let expected: HashSet<PXConfigKey> = [
        PXConfigKey::AppId,
        PXConfigKey::CookieSecret,
        PXConfigKey::AuthToken,
        PXConfigKey::LoggerAuthToken,
    ]
    .into();
    assert_eq!(keys, expected);
}

#[test]
fn apply_secret_values_overrides_config_fields() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXFROMCONFIG");
    conf.set_from_raw(PXConfigKey::CookieSecret, "config-secret");
    conf.set_from_raw(PXConfigKey::AuthToken, "config-token");
    conf.set_from_raw(PXConfigKey::LoggerAuthToken, "config-logger");

    apply_secret_values(
        &mut conf,
        &[
            (PXConfigKey::AppId, "PXFROMSECRET"),
            (PXConfigKey::CookieSecret, "secret-cookie"),
            (PXConfigKey::AuthToken, "secret-auth"),
            (PXConfigKey::LoggerAuthToken, "secret-logger"),
        ],
    );

    assert_eq!(conf.app_id, "PXFROMSECRET");
    assert_eq!(conf.cookie_secret, "secret-cookie");
    assert_eq!(conf.auth_token, "secret-auth");
    assert_eq!(conf.logger_auth_token, "secret-logger");
}

#[test]
fn apply_secret_values_partial_overlay_keeps_existing_config() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXKEPT");
    conf.set_from_raw(PXConfigKey::AuthToken, "kept-token");

    apply_secret_values(&mut conf, &[(PXConfigKey::CookieSecret, "new-secret")]);

    assert_eq!(conf.app_id, "PXKEPT");
    assert_eq!(conf.auth_token, "kept-token");
    assert_eq!(conf.cookie_secret, "new-secret");
    assert!(conf.logger_auth_token.is_empty());
}

#[test]
fn recompute_derived_uses_config_store_app_id_for_default_hosts() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXFROMCONFIG");

    recompute_derived(&mut conf, "");

    assert_eq!(conf.human_sapi_host, "sapi-PXFROMCONFIG.perimeterx.net");
    assert_eq!(
        conf.human_collector_host,
        "collector-PXFROMCONFIG.perimeterx.net"
    );
}

#[test]
fn recompute_derived_preserves_config_store_custom_hosts() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXFROMCONFIG");
    conf.set_from_raw(PXConfigKey::HumanSapiHost, "custom-sapi.example.com");
    conf.set_from_raw(
        PXConfigKey::HumanCollectorHost,
        "custom-collector.example.com",
    );

    recompute_derived(&mut conf, "");

    assert_eq!(conf.human_sapi_host, "custom-sapi.example.com");
    assert_eq!(conf.human_collector_host, "custom-collector.example.com");
}

#[test]
fn recompute_derived_updates_generated_hosts_after_secret_app_id_override() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXFROMCONFIG");
    recompute_derived(&mut conf, "");
    let app_id_before_secrets = conf.app_id.clone();

    apply_secret_values(&mut conf, &[(PXConfigKey::AppId, "PXFROMSECRET")]);
    recompute_derived(&mut conf, &app_id_before_secrets);

    assert_eq!(conf.human_sapi_host, "sapi-PXFROMSECRET.perimeterx.net");
    assert_eq!(
        conf.human_collector_host,
        "collector-PXFROMSECRET.perimeterx.net"
    );
}

#[test]
fn load_secrets_from_store_ignores_empty_store_name() {
    let mut conf = PXConfig::default();
    conf.set_from_raw(PXConfigKey::AppId, "PXKEPT");
    conf.set_from_raw(PXConfigKey::CookieSecret, "kept-cookie");
    conf.set_from_raw(PXConfigKey::AuthToken, "kept-auth");
    conf.set_from_raw(PXConfigKey::LoggerAuthToken, "kept-logger");

    load_secrets_from_store(&mut conf, "");

    assert_eq!(conf.app_id, "PXKEPT");
    assert_eq!(conf.cookie_secret, "kept-cookie");
    assert_eq!(conf.auth_token, "kept-auth");
    assert_eq!(conf.logger_auth_token, "kept-logger");
}