1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::{
  config::*,
  job::{Session, SessionBody, SessionResponseBody, ValueResponseBody},
};
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use serde::de::Visitor;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
use serde_json::Value;
use std::env::var;

// #[deprecated(
//   since = "0.10.4",
//   note = "Please use the `store` field in Parameter instead"
// )]
#[derive(Debug, PartialEq)]
pub struct Credential {
  pub value: String,
}

#[cfg_attr(feature = "cargo-clippy", allow(deprecated))]
impl Serialize for Credential {
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  where
    S: Serializer,
  {
    serializer.serialize_str(&self.value)
  }
}

struct CredentialVisitor;

#[cfg_attr(feature = "cargo-clippy", allow(deprecated))]
impl<'de> Visitor<'de> for CredentialVisitor {
  type Value = Credential;

  fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
    formatter.write_str("string or map")
  }

  fn visit_str<E>(self, value: &str) -> Result<Credential, E>
  where
    E: serde::de::Error,
  {
    Ok(Credential {
      value: value.to_string(),
    })
  }

  fn visit_string<E>(self, value: String) -> Result<Credential, E>
  where
    E: serde::de::Error,
  {
    Ok(Credential { value })
  }
}

#[cfg_attr(feature = "cargo-clippy", allow(deprecated))]
impl<'de> Deserialize<'de> for Credential {
  fn deserialize<D>(deserializer: D) -> Result<Credential, D::Error>
  where
    D: Deserializer<'de>,
  {
    deserializer.deserialize_any(CredentialVisitor)
  }
}

pub fn request_value(credential_key: &str, store_code: &str) -> Result<Value, String> {
  if vec!["env", "ENV", "environment"].contains(&store_code) {
    return var(credential_key)
      .map(Value::String)
      .map_err(|error| error.to_string());
  }

  let backend_endpoint = get_store_hostname(store_code);
  let backend_username = get_store_username(store_code);
  let backend_password = get_store_password(store_code);

  let session_url = format!("{}/sessions", backend_endpoint);
  let credential_url = format!("{}/credentials/{}", backend_endpoint, credential_key);

  let client = Client::builder().build().map_err(|e| format!("{:?}", e))?;

  let session_body = SessionBody {
    session: Session {
      email: backend_username,
      password: backend_password,
    },
  };

  let response: SessionResponseBody = client
    .post(&session_url)
    .json(&session_body)
    .send()
    .map_err(|e| e.to_string())?
    .json()
    .map_err(|e| e.to_string())?;

  let mut headers = HeaderMap::new();

  headers.insert(
    AUTHORIZATION,
    HeaderValue::from_str(&response.access_token).map_err(|e| format!("{:?}", e))?,
  );

  let client = Client::builder()
    .default_headers(headers)
    .build()
    .map_err(|e| e.to_string())?;

  let response: ValueResponseBody = client
    .get(&credential_url)
    .send()
    .map_err(|e| e.to_string())?
    .json()
    .map_err(|e| e.to_string())?;

  Ok(response.data.value)
}