aboutsummaryrefslogtreecommitdiff
path: root/src/garage/admin/key.rs
blob: 1c92670c2f18af236012e386803febe5e113a1f3 (plain) (blame)
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::collections::HashMap;

use garage_table::*;

use garage_model::helper::error::*;
use garage_model::key_table::*;

use crate::cli::*;

use super::*;

impl AdminRpcHandler {
	pub(super) async fn handle_key_cmd(&self, cmd: &KeyOperation) -> Result<AdminRpc, Error> {
		match cmd {
			KeyOperation::List => self.handle_list_keys().await,
			KeyOperation::Info(query) => self.handle_key_info(query).await,
			KeyOperation::Create(query) => self.handle_create_key(query).await,
			KeyOperation::Rename(query) => self.handle_rename_key(query).await,
			KeyOperation::Delete(query) => self.handle_delete_key(query).await,
			KeyOperation::Allow(query) => self.handle_allow_key(query).await,
			KeyOperation::Deny(query) => self.handle_deny_key(query).await,
			KeyOperation::Import(query) => self.handle_import_key(query).await,
		}
	}

	async fn handle_list_keys(&self) -> Result<AdminRpc, Error> {
		let key_ids = self
			.garage
			.key_table
			.get_range(
				&EmptyKey,
				None,
				Some(KeyFilter::Deleted(DeletedFilter::NotDeleted)),
				10000,
				EnumerationOrder::Forward,
			)
			.await?
			.iter()
			.map(|k| (k.key_id.to_string(), k.params().unwrap().name.get().clone()))
			.collect::<Vec<_>>();
		Ok(AdminRpc::KeyList(key_ids))
	}

	async fn handle_key_info(&self, query: &KeyInfoOpt) -> Result<AdminRpc, Error> {
		let mut key = self
			.garage
			.key_helper()
			.get_existing_matching_key(&query.key_pattern)
			.await?;

		if !query.show_secret {
			key.state.as_option_mut().unwrap().secret_key = "(redacted)".into();
		}

		self.key_info_result(key).await
	}

	async fn handle_create_key(&self, query: &KeyNewOpt) -> Result<AdminRpc, Error> {
		let key = Key::new(&query.name);
		self.garage.key_table.insert(&key).await?;
		self.key_info_result(key).await
	}

	async fn handle_rename_key(&self, query: &KeyRenameOpt) -> Result<AdminRpc, Error> {
		let mut key = self
			.garage
			.key_helper()
			.get_existing_matching_key(&query.key_pattern)
			.await?;
		key.params_mut()
			.unwrap()
			.name
			.update(query.new_name.clone());
		self.garage.key_table.insert(&key).await?;
		self.key_info_result(key).await
	}

	async fn handle_delete_key(&self, query: &KeyDeleteOpt) -> Result<AdminRpc, Error> {
		let key_helper = self.garage.key_helper();

		let mut key = key_helper
			.get_existing_matching_key(&query.key_pattern)
			.await?;

		if !query.yes {
			return Err(Error::BadRequest(
				"Add --yes flag to really perform this operation".to_string(),
			));
		}

		key_helper.delete_key(&mut key).await?;

		Ok(AdminRpc::Ok(format!(
			"Key {} was deleted successfully.",
			key.key_id
		)))
	}

	async fn handle_allow_key(&self, query: &KeyPermOpt) -> Result<AdminRpc, Error> {
		let mut key = self
			.garage
			.key_helper()
			.get_existing_matching_key(&query.key_pattern)
			.await?;
		if query.create_bucket {
			key.params_mut().unwrap().allow_create_bucket.update(true);
		}
		self.garage.key_table.insert(&key).await?;
		self.key_info_result(key).await
	}

	async fn handle_deny_key(&self, query: &KeyPermOpt) -> Result<AdminRpc, Error> {
		let mut key = self
			.garage
			.key_helper()
			.get_existing_matching_key(&query.key_pattern)
			.await?;
		if query.create_bucket {
			key.params_mut().unwrap().allow_create_bucket.update(false);
		}
		self.garage.key_table.insert(&key).await?;
		self.key_info_result(key).await
	}

	async fn handle_import_key(&self, query: &KeyImportOpt) -> Result<AdminRpc, Error> {
		if !query.yes {
			return Err(Error::BadRequest("This command is intended to re-import keys that were previously generated by Garage. If you want to create a new key, use `garage key new` instead. Add the --yes flag if you really want to re-import a key.".to_string()));
		}

		let prev_key = self.garage.key_table.get(&EmptyKey, &query.key_id).await?;
		if prev_key.is_some() {
			return Err(Error::BadRequest(format!("Key {} already exists in data store. Even if it is deleted, we can't let you create a new key with the same ID. Sorry.", query.key_id)));
		}

		let imported_key = Key::import(&query.key_id, &query.secret_key, &query.name)
			.ok_or_bad_request("Invalid key format")?;
		self.garage.key_table.insert(&imported_key).await?;

		self.key_info_result(imported_key).await
	}

	async fn key_info_result(&self, key: Key) -> Result<AdminRpc, Error> {
		let mut relevant_buckets = HashMap::new();

		for (id, _) in key
			.state
			.as_option()
			.unwrap()
			.authorized_buckets
			.items()
			.iter()
		{
			if let Some(b) = self.garage.bucket_table.get(&EmptyKey, id).await? {
				relevant_buckets.insert(*id, b);
			}
		}

		Ok(AdminRpc::KeyInfo(key, relevant_buckets))
	}
}