]> git.proxmox.com Git - proxmox-backup.git/blob - src/bin/proxmox_backup_manager/user.rs
add pbs-tools subcrate
[proxmox-backup.git] / src / bin / proxmox_backup_manager / user.rs
1 use anyhow::Error;
2 use serde_json::Value;
3
4 use std::collections::HashMap;
5
6 use proxmox::api::{api, cli::*, RpcEnvironment, ApiHandler};
7
8 use proxmox_backup::config;
9 use proxmox_backup::api2;
10 use proxmox_backup::api2::types::{ACL_PATH_SCHEMA, Authid, Userid};
11
12 fn render_expire(value: &Value, _record: &Value) -> Result<String, Error> {
13 let never = String::from("never");
14 if value.is_null() { return Ok(never); }
15 let text = match value.as_i64() {
16 Some(epoch) if epoch == 0 => never,
17 Some(epoch) => {
18 if let Ok(epoch_string) = proxmox::tools::time::strftime_local("%c", epoch as i64) {
19 epoch_string
20 } else {
21 epoch.to_string()
22 }
23 },
24 None => value.to_string(),
25 };
26 Ok(text)
27 }
28
29 #[api(
30 input: {
31 properties: {
32 "output-format": {
33 schema: OUTPUT_FORMAT,
34 optional: true,
35 },
36 }
37 }
38 )]
39 /// List configured users.
40 fn list_users(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
41
42 let output_format = get_output_format(&param);
43
44 let info = &api2::access::user::API_METHOD_LIST_USERS;
45 let mut data = match info.handler {
46 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
47 _ => unreachable!(),
48 };
49
50 let options = default_table_format_options()
51 .column(ColumnConfig::new("userid"))
52 .column(
53 ColumnConfig::new("enable")
54 .renderer(pbs_tools::format::render_bool_with_default_true)
55 )
56 .column(
57 ColumnConfig::new("expire")
58 .renderer(render_expire)
59 )
60 .column(ColumnConfig::new("firstname"))
61 .column(ColumnConfig::new("lastname"))
62 .column(ColumnConfig::new("email"))
63 .column(ColumnConfig::new("comment"));
64
65 format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
66
67 Ok(Value::Null)
68 }
69
70 #[api(
71 input: {
72 properties: {
73 "output-format": {
74 schema: OUTPUT_FORMAT,
75 optional: true,
76 },
77 userid: {
78 type: Userid,
79 }
80 }
81 }
82 )]
83 /// List tokens associated with user.
84 fn list_tokens(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
85
86 let output_format = get_output_format(&param);
87
88 let info = &api2::access::user::API_METHOD_LIST_TOKENS;
89 let mut data = match info.handler {
90 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
91 _ => unreachable!(),
92 };
93
94 let options = default_table_format_options()
95 .column(ColumnConfig::new("tokenid"))
96 .column(
97 ColumnConfig::new("enable")
98 .renderer(pbs_tools::format::render_bool_with_default_true)
99 )
100 .column(
101 ColumnConfig::new("expire")
102 .renderer(render_expire)
103 )
104 .column(ColumnConfig::new("comment"));
105
106 format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
107
108 Ok(Value::Null)
109 }
110
111
112 #[api(
113 input: {
114 properties: {
115 "output-format": {
116 schema: OUTPUT_FORMAT,
117 optional: true,
118 },
119 "auth-id": {
120 type: Authid,
121 },
122 path: {
123 schema: ACL_PATH_SCHEMA,
124 optional: true,
125 },
126 }
127 }
128 )]
129 /// List permissions of user/token.
130 fn list_permissions(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
131
132 let output_format = get_output_format(&param);
133
134 let info = &api2::access::API_METHOD_LIST_PERMISSIONS;
135 let data = match info.handler {
136 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
137 _ => unreachable!(),
138 };
139
140 if output_format == "text" {
141 println!("Privileges with (*) have the propagate flag set\n");
142 let data:HashMap<String, HashMap<String, bool>> = serde_json::from_value(data)?;
143 let mut paths:Vec<String> = data.keys().cloned().collect();
144 paths.sort_unstable();
145 for path in paths {
146 println!("Path: {}", path);
147 let priv_map = data.get(&path).unwrap();
148 let mut privs:Vec<String> = priv_map.keys().cloned().collect();
149 if privs.is_empty() {
150 println!("- NoAccess");
151 } else {
152 privs.sort_unstable();
153 for privilege in privs {
154 if *priv_map.get(&privilege).unwrap() {
155 println!("- {} (*)", privilege);
156 } else {
157 println!("- {}", privilege);
158 }
159 }
160 }
161 }
162 } else {
163 format_and_print_result(&data, &output_format);
164 }
165
166 Ok(Value::Null)
167 }
168
169
170 pub fn user_commands() -> CommandLineInterface {
171
172 let cmd_def = CliCommandMap::new()
173 .insert("list", CliCommand::new(&&API_METHOD_LIST_USERS))
174 .insert(
175 "create",
176 // fixme: howto handle password parameter?
177 CliCommand::new(&api2::access::user::API_METHOD_CREATE_USER)
178 .arg_param(&["userid"])
179 )
180 .insert(
181 "update",
182 CliCommand::new(&api2::access::user::API_METHOD_UPDATE_USER)
183 .arg_param(&["userid"])
184 .completion_cb("userid", config::user::complete_userid)
185 )
186 .insert(
187 "remove",
188 CliCommand::new(&api2::access::user::API_METHOD_DELETE_USER)
189 .arg_param(&["userid"])
190 .completion_cb("userid", config::user::complete_userid)
191 )
192 .insert(
193 "list-tokens",
194 CliCommand::new(&&API_METHOD_LIST_TOKENS)
195 .arg_param(&["userid"])
196 .completion_cb("userid", config::user::complete_userid)
197 )
198 .insert(
199 "generate-token",
200 CliCommand::new(&api2::access::user::API_METHOD_GENERATE_TOKEN)
201 .arg_param(&["userid", "tokenname"])
202 .completion_cb("userid", config::user::complete_userid)
203 )
204 .insert(
205 "delete-token",
206 CliCommand::new(&api2::access::user::API_METHOD_DELETE_TOKEN)
207 .arg_param(&["userid", "tokenname"])
208 .completion_cb("userid", config::user::complete_userid)
209 .completion_cb("tokenname", config::user::complete_token_name)
210 )
211 .insert(
212 "permissions",
213 CliCommand::new(&&API_METHOD_LIST_PERMISSIONS)
214 .arg_param(&["auth-id"])
215 .completion_cb("auth-id", config::user::complete_authid)
216 .completion_cb("path", config::datastore::complete_acl_path)
217 );
218
219 cmd_def.into()
220 }