Skip to content

Commit 9eddcdc

Browse files
author
Paul Yang
authored
Merge pull request #136 from wa5i/cli
Implemented CLI commands for secrets and it's subcommands.
2 parents 3323c86 + 597ab07 commit 9eddcdc

36 files changed

+1476
-512
lines changed

src/api/auth_token.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use std::collections::HashMap;
2+
3+
use derive_more::Deref;
4+
use serde::{Deserialize, Serialize};
5+
6+
use super::{Client, HttpResponse};
7+
use crate::errors::RvError;
8+
9+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10+
pub struct TokenInput {
11+
#[serde(default)]
12+
pub id: String,
13+
#[serde(default)]
14+
pub policies: Vec<String>,
15+
#[serde(default)]
16+
pub meta: HashMap<String, String>,
17+
#[serde(default)]
18+
pub lease: String,
19+
#[serde(default)]
20+
pub ttl: String,
21+
#[serde(default)]
22+
pub explicit_max_ttl: String,
23+
#[serde(default)]
24+
pub period: String,
25+
#[serde(default)]
26+
pub no_parent: bool,
27+
#[serde(default)]
28+
pub no_default_policy: bool,
29+
pub display_name: String,
30+
pub num_uses: u32,
31+
#[serde(default)]
32+
pub renewable: bool,
33+
#[serde(default, rename = "type")]
34+
pub logical_type: String,
35+
}
36+
37+
#[derive(Deref)]
38+
pub struct TokenAuth<'a> {
39+
#[deref]
40+
pub client: &'a Client,
41+
}
42+
43+
impl Client {
44+
pub fn token(&self) -> TokenAuth {
45+
TokenAuth { client: self }
46+
}
47+
}
48+
49+
impl TokenAuth<'_> {
50+
pub fn create(&self, input: &TokenInput) -> Result<HttpResponse, RvError> {
51+
let data = serde_json::to_value(input)?;
52+
self.request_write("/v1/auth/token/create", data.as_object().cloned())
53+
}
54+
55+
pub fn create_orphan(&self, input: &TokenInput) -> Result<HttpResponse, RvError> {
56+
let data = serde_json::to_value(input)?;
57+
self.request_write("/v1/auth/token/create-orphan", data.as_object().cloned())
58+
}
59+
60+
pub fn create_with_role(&self, input: &TokenInput, role_name: &str) -> Result<HttpResponse, RvError> {
61+
let data = serde_json::to_value(input)?;
62+
self.request_write(&format!("/v1/auth/token/create/{}", role_name), data.as_object().cloned())
63+
}
64+
65+
pub fn lookup(&self, token: &str) -> Result<HttpResponse, RvError> {
66+
let data = serde_json::json!({
67+
"token": token,
68+
});
69+
self.request_write("/v1/auth/token/lookup", data.as_object().cloned())
70+
}
71+
72+
pub fn lookup_accessor(&self, accessor: &str) -> Result<HttpResponse, RvError> {
73+
let data = serde_json::json!({
74+
"accessor": accessor,
75+
});
76+
self.request_write("/v1/auth/token/lookup-accessor", data.as_object().cloned())
77+
}
78+
79+
pub fn lookup_self(&self) -> Result<HttpResponse, RvError> {
80+
self.request_get("/v1/auth/token/lookup-self")
81+
}
82+
83+
pub fn renew(&self, token: &str, increment: u32) -> Result<HttpResponse, RvError> {
84+
let data = serde_json::json!({
85+
"token": token,
86+
"increment": increment,
87+
});
88+
self.request_write("/v1/auth/token/renew", data.as_object().cloned())
89+
}
90+
91+
pub fn renew_accessor(&self, accessor: &str, increment: u32) -> Result<HttpResponse, RvError> {
92+
let data = serde_json::json!({
93+
"accessor": accessor,
94+
"increment": increment,
95+
});
96+
self.request_write("/v1/auth/token/renew-accessor", data.as_object().cloned())
97+
}
98+
99+
pub fn renew_self(&self, increment: u32) -> Result<HttpResponse, RvError> {
100+
let data = serde_json::json!({
101+
"increment": increment,
102+
});
103+
self.request_write("/v1/auth/token/renew-self", data.as_object().cloned())
104+
}
105+
106+
pub fn renew_token_as_self(&self, token: &str, increment: u32) -> Result<HttpResponse, RvError> {
107+
let mut client = self.client.clone();
108+
client.token = token.to_string();
109+
let data = serde_json::json!({
110+
"increment": increment,
111+
});
112+
client.request_write("/v1/auth/token/renew-self", data.as_object().cloned())
113+
}
114+
115+
pub fn revoke_accessor(&self, accessor: &str) -> Result<HttpResponse, RvError> {
116+
let data = serde_json::json!({
117+
"accessor": accessor,
118+
});
119+
self.request_write("/v1/auth/token/revoke-accessor", data.as_object().cloned())
120+
}
121+
122+
pub fn revoke_orphan(&self, token: &str) -> Result<HttpResponse, RvError> {
123+
let data = serde_json::json!({
124+
"token": token,
125+
});
126+
self.request_put("/v1/auth/token/revoke-orphan", data.as_object().cloned())
127+
}
128+
129+
pub fn revoke_self(&self) -> Result<HttpResponse, RvError> {
130+
self.request_put("/v1/auth/token/revoke-self", None)
131+
}
132+
133+
pub fn revoke_tree(&self, token: &str) -> Result<HttpResponse, RvError> {
134+
let data = serde_json::json!({
135+
"token": token,
136+
});
137+
self.request_put("/v1/auth/token/revoke", data.as_object().cloned())
138+
}
139+
}

src/api/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct TLSConfig {
1717
client_config: ClientConfig,
1818
}
1919

20-
#[derive(Default)]
20+
#[derive(Default, Clone)]
2121
pub struct TLSConfigBuilder {
2222
pub server_ca_pem: Option<Vec<u8>>,
2323
pub client_cert_pem: Option<Vec<u8>>,
@@ -26,7 +26,7 @@ pub struct TLSConfigBuilder {
2626
pub insecure: bool,
2727
}
2828

29-
#[derive(Default)]
29+
#[derive(Default, Clone)]
3030
pub struct Client {
3131
#[default("https://127.0.0.1:8200".into())]
3232
pub address: String,

src/api/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use serde_json::Value;
44

55
pub mod auth;
6+
pub mod auth_token;
67
pub mod client;
78
pub mod logical;
89
pub mod secret;

src/api/secret.rs

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use std::collections::HashMap;
33
use serde::{Deserialize, Serialize};
44
use serde_json::{Map, Value};
55

6-
#[derive(Debug, Clone, Serialize, Deserialize)]
6+
use crate::{errors::RvError, rv_error_string};
7+
8+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
79
pub struct Secret {
810
#[serde(default)]
911
pub request_id: String,
@@ -19,7 +21,7 @@ pub struct Secret {
1921
pub auth: Option<SecretAuth>,
2022
}
2123

22-
#[derive(Debug, Clone, Serialize, Deserialize)]
24+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2325
pub struct SecretAuth {
2426
#[serde(default)]
2527
pub client_token: String,
@@ -36,7 +38,131 @@ pub struct SecretAuth {
3638
#[serde(default)]
3739
pub entity_id: String,
3840
#[serde(default)]
39-
pub lease_duration: u32,
41+
pub lease_duration: u64,
4042
#[serde(default)]
4143
pub renewable: bool,
4244
}
45+
46+
impl Secret {
47+
pub fn token_is_renewable(&self) -> Result<bool, RvError> {
48+
if let Some(auth) = &self.auth {
49+
return Ok(auth.renewable);
50+
}
51+
52+
let Some(renewable_value) = self.data.get("renewable") else {
53+
return Ok(false);
54+
};
55+
56+
let Some(renewable) = renewable_value.as_bool() else {
57+
return Err(rv_error_string!("token id found but in the wrong format"));
58+
};
59+
60+
Ok(renewable)
61+
}
62+
63+
pub fn token_id(&self) -> Result<String, RvError> {
64+
if let Some(auth) = &self.auth {
65+
if !auth.client_token.is_empty() {
66+
return Ok(auth.client_token.clone());
67+
}
68+
}
69+
70+
let Some(id_value) = self.data.get("id") else {
71+
return Ok("".into());
72+
};
73+
74+
let Some(id) = id_value.as_str() else {
75+
return Err(rv_error_string!("token id found but in the wrong format"));
76+
};
77+
78+
Ok(id.to_string())
79+
}
80+
81+
pub fn token_accessor(&self) -> Result<String, RvError> {
82+
if let Some(auth) = &self.auth {
83+
if !auth.accessor.is_empty() {
84+
return Ok(auth.accessor.clone());
85+
}
86+
}
87+
88+
let Some(accessor_value) = self.data.get("accessor") else {
89+
return Ok("".into());
90+
};
91+
92+
let Some(accessor) = accessor_value.as_str() else {
93+
return Err(rv_error_string!("token accessor found but in the wrong format"));
94+
};
95+
96+
Ok(accessor.to_string())
97+
}
98+
99+
pub fn token_policies(&self) -> Result<Vec<String>, RvError> {
100+
if let Some(auth) = &self.auth {
101+
if !auth.policies.is_empty() {
102+
return Ok(auth.policies.clone());
103+
}
104+
}
105+
106+
let Some(policies_value) = self.data.get("policies") else {
107+
return Ok(vec![]);
108+
};
109+
110+
let Some(policies) = policies_value.as_array() else {
111+
return Err(rv_error_string!("token policies found but in the wrong format"));
112+
};
113+
114+
Ok(policies.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())
115+
}
116+
117+
pub fn token_ttl(&self) -> Result<u64, RvError> {
118+
if let Some(auth) = &self.auth {
119+
return Ok(auth.lease_duration);
120+
}
121+
122+
let Some(ttl_value) = self.data.get("ttl") else {
123+
return Ok(0);
124+
};
125+
126+
let Some(ttl) = ttl_value.as_u64() else {
127+
return Err(rv_error_string!("token ttl found but in the wrong format"));
128+
};
129+
130+
Ok(ttl)
131+
}
132+
133+
pub fn token_metadata(&self) -> Result<HashMap<String, String>, RvError> {
134+
if let Some(auth) = &self.auth {
135+
if !auth.metadata.is_empty() {
136+
return Ok(auth.metadata.clone());
137+
}
138+
}
139+
140+
if let Some(data) = self.data.get("metadata") {
141+
let Some(metadata) = data.as_object() else {
142+
return Err(rv_error_string!("token metadata found but in the wrong format"));
143+
};
144+
145+
return Ok(metadata.into_iter().map(|(k, v)| (k.to_string(), value_to_string(v))).collect());
146+
}
147+
148+
if let Some(data) = self.data.get("meta") {
149+
let Some(meta) = data.as_object() else {
150+
return Err(rv_error_string!("token meta found but in the wrong format"));
151+
};
152+
153+
return Ok(meta.into_iter().map(|(k, v)| (k.to_string(), value_to_string(v))).collect());
154+
}
155+
156+
Ok(HashMap::new())
157+
}
158+
}
159+
160+
fn value_to_string(value: &Value) -> String {
161+
match value {
162+
Value::String(s) => s.clone(),
163+
Value::Number(n) => n.to_string(),
164+
Value::Bool(b) => b.to_string(),
165+
Value::Null => "null".to_string(),
166+
_ => "".to_string(),
167+
}
168+
}

0 commit comments

Comments
 (0)