From 4516135d2eb67d16cb084c19cb766388136b12b5 Mon Sep 17 00:00:00 2001 From: ixe013 Date: Mon, 15 Dec 2025 23:08:20 -0500 Subject: [PATCH] Added a function to compute the flag entirely from parameters (and environment) --- .github/workflows/build-and-test.yml | 5 ++ Cargo.toml | 4 +- example/testclient.py | 2 +- include/ctflags.h | 4 +- pyproject.toml | 2 +- src/flags.rs | 72 +++++----------------------- src/flags_adapter.rs | 6 +-- src/python_api.rs | 6 +-- 8 files changed, 29 insertions(+), 72 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a550845..fcded6b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -29,10 +29,15 @@ jobs: test: runs-on: ubuntu-latest + env: + CTFLAGS_SEED_FILE_NAME: ctflag.seed steps: - name: Checkout source code uses: actions/checkout@v4 + - name: Simulate user registration + run: echo -n segg1545 | tee ${CTFLAGS_SEED_FILE_NAME} + - name: Test the library run: cargo test diff --git a/Cargo.toml b/Cargo.toml index 34e8b99..9469606 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ctflags" -version = "0.3.6" +version = "0.4.0" edition = "2024" [dependencies] @@ -11,8 +11,6 @@ tracing = "*" pyo3 = { version = "*", features = ["extension-module", "abi3-py37"], optional = true } [lib] -# "lib" est le type par défaut pour l'écosystème Rust. -# "cdylib" est une librairie dynamique de style C, idéale pour être chargée par d'autres langages. crate-type = ["lib", "staticlib", "cdylib"] [features] diff --git a/example/testclient.py b/example/testclient.py index 98a1efd..8409722 100644 --- a/example/testclient.py +++ b/example/testclient.py @@ -15,7 +15,7 @@ def main(): print(f"Flag with salt: {flag_salt}") # Test with a string context - with_string_context = ctflags.format_flag_from_string_context("segg1545", "example") + with_string_context = ctflags.format_flag_from_context("segg1545", "example") print(f"Flag with string context is {with_string_context}") assert with_string_context == "flag(example).5f1b958992ca66c09c0ac9170fce85de" diff --git a/include/ctflags.h b/include/ctflags.h index 6e8526b..0dac19d 100644 --- a/include/ctflags.h +++ b/include/ctflags.h @@ -13,7 +13,7 @@ extern "C" { const char* ctflags_get_seed_or_null(); void ctflags_free_string(const char* ptr); const char* ctflags_format_flag(const char* step, const char* salt); - const char* ctflags_format_flag_from_string_context(const char* context, const char* step, const char* salt); + const char* ctflags_format_flag_from_context(const char* context, const char* step, const char* salt); } namespace ctflags { @@ -64,7 +64,7 @@ class Flag { : m_ptr(ctflags_format_flag(step, salt)) {} Flag(const char* context, const char* step, const char* salt = nullptr) - : m_ptr(ctflags_format_flag_from_string_context(context, step, salt)) {} + : m_ptr(ctflags_format_flag_from_context(context, step, salt)) {} ~Flag() { ctflags_free_string(m_ptr); diff --git a/pyproject.toml b/pyproject.toml index 5b13e98..f34eaa7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "ctflags" -version = "0.3.6" +version = "0.4.0" requires-python = ">=3.7" classifiers = [ "Programming Language :: Rust", diff --git a/src/flags.rs b/src/flags.rs index aba4c7d..729bb67 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -1,5 +1,4 @@ use std::env; -use std::path::PathBuf; use crate::seed; @@ -8,51 +7,27 @@ use crate::seed; const GLOBAL_SALT_ENV_VAR: &str = "FLAG_GLOBAL_SALT"; -pub fn compute_flag_from_context(context: &PathBuf, step: &str, salt: Option) -> String { +pub fn compute_flag_from_context(context: &str, step: &str, salt: Option) -> String { let mut digest = md5::Context::new(); digest.consume(step); - digest.consume(seed::get_from_context_or_null(context)); + if let Ok(global_salt) = env::var(GLOBAL_SALT_ENV_VAR) { + digest.consume(global_salt); + } if let Some(s) = salt { digest.consume(s); } - format!("{:x}", digest.finalize()) -} - -pub fn compute_flag_from_string_context(context: &str, step: &str, salt: Option) -> String { - let mut digest = md5::Context::new(); - - digest.consume(step); - digest.consume(context); - if let Some(s) = salt { - digest.consume(s); - } - format!("{:x}", digest.finalize()) } pub fn compute_flag(step: &str, salt: Option) -> String { - let mut digest = md5::Context::new(); - - digest.consume(step); - - if let Ok(global_salt) = env::var(GLOBAL_SALT_ENV_VAR) { - digest.consume(global_salt); - } - - if let Some(app_salt) = salt { - digest.consume(app_salt); - } - - digest.consume(seed::get_or_null()); - - format!("{:x}", digest.finalize()) + compute_flag_from_context(&seed::get_or_null(), step, salt) } @@ -60,8 +35,8 @@ pub fn format_flag(step: &str, salt: Option) -> String { format!("flag({step}).{}", compute_flag(step, salt)) } -pub fn format_flag_from_string_context(context: &str, step: &str, salt: Option) -> String { - format!("flag({step}).{}", compute_flag_from_string_context(context, step, salt)) +pub fn format_flag_from_context(context: &str, step: &str, salt: Option) -> String { + format!("flag({step}).{}", compute_flag_from_context(context, step, salt)) } @@ -72,40 +47,19 @@ mod tests { #[test] fn legacy_environment_based_flag() { assert_eq!(compute_flag("example", None), - "1a79a4d60de6718e8e5b326e338ae533"); + "5f1b958992ca66c09c0ac9170fce85de"); assert_eq!(compute_flag("example", Some("app noise".to_string())), - "5251b4290fb05756da94df1ec637b5a7"); + "c37b2bf9e83b0c886c166bbb7e28c8fe"); } #[test] - fn same_flag_increasing_noise() { - // Create a context file for this test (to avoid collision with other tests) - let context = seed::create_seed_context(".__example1"); - // Save a seed to that context file - assert!(!seed::set_from_context(&context, "segg1545").is_err()); - - assert_eq!(compute_flag_from_context(&context, "example", None), - "5f1b958992ca66c09c0ac9170fce85de"); - - assert_eq!(compute_flag_from_context(&context, "example", Some("app noise".to_string())), - "98bf92ea5a1438ed465490c9c2396409"); - - let _ = seed::clear_from_context(&context); + fn same_flag_with_noise() { + assert_eq!(compute_flag_from_context("segg1545", "example", Some("not a flag".to_string())), + "54ed3a6a399869c751820aee6046668b"); } #[test] fn example_flag() { - let context = seed::create_seed_context(".__example2"); - assert!(!seed::set_from_context(&context, "segg1545").is_err()); - - assert_eq!(compute_flag_from_context(&context, "example", None), "5f1b958992ca66c09c0ac9170fce85de"); - - let _ = seed::clear_from_context(&context); - } - - #[test] - // Equivalent to existing example_flag test - fn example_flag_with_string_context() { - assert_eq!(compute_flag_from_string_context("segg1545", "example", None), "5f1b958992ca66c09c0ac9170fce85de"); + assert_eq!(compute_flag_from_context("segg1545", "example", None), "5f1b958992ca66c09c0ac9170fce85de"); } } diff --git a/src/flags_adapter.rs b/src/flags_adapter.rs index 4349ff6..df11384 100644 --- a/src/flags_adapter.rs +++ b/src/flags_adapter.rs @@ -2,10 +2,10 @@ use std::ffi::{CStr, CString}; use std::os::raw::c_char; // On importe la fonction Rust originale qu'on veut exposer -use crate::flags::{format_flag, format_flag_from_string_context}; +use crate::flags::{format_flag, format_flag_from_context}; #[unsafe(no_mangle)] -pub extern "C" fn ctflags_format_flag_from_string_context(context: *const c_char, step: *const c_char, salt: *const c_char) -> *const c_char { +pub extern "C" fn ctflags_format_flag_from_context(context: *const c_char, step: *const c_char, salt: *const c_char) -> *const c_char { unsafe { let context_str = CStr::from_ptr(context).to_str().expect("context contains invalid UTF-8"); let step_str = CStr::from_ptr(step).to_str().expect("step contains invalid UTF-8"); @@ -17,7 +17,7 @@ pub extern "C" fn ctflags_format_flag_from_string_context(context: *const c_char Some(salt_str.to_string()) }; - let result_string = format_flag_from_string_context(context_str, step_str, salt_option); + let result_string = format_flag_from_context(context_str, step_str, salt_option); let c_result = CString::new(result_string).unwrap(); c_result.into_raw() diff --git a/src/python_api.rs b/src/python_api.rs index 7aae6f2..3916da3 100644 --- a/src/python_api.rs +++ b/src/python_api.rs @@ -9,8 +9,8 @@ fn format_flag(step: &str, salt: Option) -> String { #[pyfunction] #[pyo3(signature = (context, step, salt=None))] -fn format_flag_from_string_context(context: &str, step: &str, salt: Option) -> String { - flags::format_flag_from_string_context(context, step, salt) +fn format_flag_from_context(context: &str, step: &str, salt: Option) -> String { + flags::format_flag_from_context(context, step, salt) } #[pyfunction] @@ -21,7 +21,7 @@ fn get_seed_or_null() -> String { #[pymodule] fn ctflags(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(format_flag, m)?)?; - m.add_function(wrap_pyfunction!(format_flag_from_string_context, m)?)?; + m.add_function(wrap_pyfunction!(format_flag_from_context, m)?)?; m.add_function(wrap_pyfunction!(get_seed_or_null, m)?)?; Ok(()) }