fhttp-core 1.3.1

core library for the fhttp tool
Documentation
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use crate::{Result, FhttpError, Config};
use std::process::Command;

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ProfileVariable {
    StringValue(String),
    PassSecret {
        pass: String,
        #[serde(skip)]
        cache: RefCell<Option<String>>
    },
    Request {
        request: String,
    },
}

impl ProfileVariable {

    pub fn get(
        &self,
        config: &Config,
    ) -> Result<String> {
        match self {
            ProfileVariable::StringValue(ref value) => Ok(value.to_owned()),
            ProfileVariable::PassSecret { pass: path, cache } => {
                if cache.borrow().is_none() {
                    config.log(2, format!("resolving pass secret '{}'... ", &path));
                    let value = resolve_pass(&path)?.trim().to_owned();
                    config.logln(2, "done");
                    cache.borrow_mut().replace(value);
                }

                Ok(cache.borrow().as_ref().unwrap().clone())
            }
            ProfileVariable::Request { request: _ } => panic!("ProfileVariable::Request cannot resolve by itself"),
        }
    }

}

fn resolve_pass(path: &str) -> Result<String> {
    let output = Command::new("pass")
        .args(&[path])
        .output()
        .unwrap();

    if output.status.success() {
        let output = output.stdout;
        Ok(String::from_utf8(output).unwrap())
    } else {
        let stderr = String::from_utf8(output.stderr).unwrap();
        Err(FhttpError::new(
            format!("pass returned an error: '{}'", stderr)
        ))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use indoc::indoc;

    #[test]
    fn deserialize_string_value() {
        let input = "\"foo\"";
        let result = serde_json::from_str::<ProfileVariable>(&input).unwrap();
        assert_eq!(result, ProfileVariable::StringValue("foo".into()));
    }

    #[test]
    fn deserialize_pass_secret() {
        let input = indoc!(r##"
            {
                "pass": "foo/bar"
            }
        "##);
        let result = serde_json::from_str::<ProfileVariable>(&input).unwrap();
        assert_eq!(result, ProfileVariable::PassSecret { pass: "foo/bar".into(), cache: RefCell::new(None) });
    }

}