Skip to main content

dvrip_rs/commands/
user_management.rs

1use crate::Authentication;
2use crate::constants::OK_CODES;
3use crate::dvrip::DVRIPCam;
4use crate::error::Result;
5use crate::protocol::sofia_hash;
6use async_trait::async_trait;
7use serde_json::{Value, json};
8
9#[async_trait]
10pub trait UserManagement: Send + Sync {
11    /// Get the list of authorities
12    async fn get_authority_list(&mut self) -> Result<Vec<Value>>;
13
14    /// Get the list of groups
15    async fn get_groups(&mut self) -> Result<Vec<Value>>;
16
17    /// Add a new group
18    async fn add_group(
19        &mut self,
20        name: &str,
21        comment: &str,
22        auth: Option<Vec<Value>>,
23    ) -> Result<bool>;
24
25    /// Modify an existing group
26    async fn modify_group(
27        &mut self,
28        name: &str,
29        newname: Option<&str>,
30        comment: Option<&str>,
31        auth: Option<Vec<Value>>,
32    ) -> Result<bool>;
33
34    /// Delete a group
35    async fn delete_group(&mut self, name: &str) -> Result<bool>;
36
37    /// Get the list of users
38    async fn get_users(&mut self) -> Result<Vec<Value>>;
39
40    /// Add a new user
41    async fn add_user(
42        &mut self,
43        name: &str,
44        password: &str,
45        comment: &str,
46        group: &str,
47        auth: Option<Vec<Value>>,
48        sharable: bool,
49    ) -> Result<bool>;
50
51    /// Modify an existing user
52    async fn modify_user(
53        &mut self,
54        name: &str,
55        newname: Option<&str>,
56        comment: Option<&str>,
57        group: Option<&str>,
58        auth: Option<Vec<Value>>,
59        sharable: Option<bool>,
60    ) -> Result<bool>;
61
62    /// Delete a user
63    async fn delete_user(&mut self, name: &str) -> Result<bool>;
64}
65
66#[async_trait]
67impl UserManagement for DVRIPCam {
68    async fn get_authority_list(&mut self) -> Result<Vec<Value>> {
69        let data = self.get_command("AuthorityList", None).await?;
70        if let Some(auth_list) = data.get("AuthorityList").and_then(|v| v.as_array()) {
71            return Ok(auth_list.clone());
72        }
73        Ok(vec![])
74    }
75
76    async fn get_groups(&mut self) -> Result<Vec<Value>> {
77        let data = self.get_command("Groups", None).await?;
78        if let Some(groups) = data.get("Groups").and_then(|v| v.as_array()) {
79            return Ok(groups.clone());
80        }
81        Ok(vec![])
82    }
83
84    async fn add_group(
85        &mut self,
86        name: &str,
87        comment: &str,
88        auth: Option<Vec<Value>>,
89    ) -> Result<bool> {
90        let auth_list = match auth {
91            Some(a) => a,
92            None => self.get_authority_list().await?,
93        };
94
95        let data = json!({
96            "Group": {
97                "AuthorityList": auth_list,
98                "Memo": comment,
99                "Name": name,
100            }
101        });
102
103        let reply = self.set_command("AddGroup", data, None).await?;
104        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
105            return Ok(OK_CODES.contains(&(ret as u32)));
106        }
107        Ok(false)
108    }
109
110    async fn modify_group(
111        &mut self,
112        name: &str,
113        newname: Option<&str>,
114        comment: Option<&str>,
115        auth: Option<Vec<Value>>,
116    ) -> Result<bool> {
117        let groups = self.get_groups().await?;
118        let group = groups
119            .iter()
120            .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(name))
121            .ok_or_else(|| {
122                crate::error::DVRIPError::Unknown(format!("Group '{}' not found", name))
123            })?;
124
125        let auth_list = auth.unwrap_or_else(|| {
126            group
127                .get("AuthorityList")
128                .and_then(|a| a.as_array())
129                .cloned()
130                .unwrap_or_default()
131        });
132
133        let data = json!({
134            "Group": {
135                "AuthorityList": auth_list,
136                "Memo": comment.or_else(|| group.get("Memo").and_then(|m| m.as_str())).unwrap_or_default(),
137                "Name": newname.unwrap_or(name),
138            },
139            "GroupName": name,
140        });
141
142        let reply = self.set_command("ModifyGroup", data, None).await?;
143        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
144            return Ok(OK_CODES.contains(&(ret as u32)));
145        }
146        Ok(false)
147    }
148
149    async fn delete_group(&mut self, name: &str) -> Result<bool> {
150        let session = self.session_id();
151        let data = json!({
152            "Name": name,
153            "SessionID": format!("0x{:08X}", session),
154        });
155
156        let reply = self.set_command("DelGroup", data, None).await?;
157        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
158            return Ok(OK_CODES.contains(&(ret as u32)));
159        }
160        Ok(false)
161    }
162
163    async fn get_users(&mut self) -> Result<Vec<Value>> {
164        let data = self.get_command("Users", None).await?;
165        if let Some(users) = data.get("Users").and_then(|v| v.as_array()) {
166            return Ok(users.clone());
167        }
168        Ok(vec![])
169    }
170
171    async fn add_user(
172        &mut self,
173        name: &str,
174        password: &str,
175        comment: &str,
176        group: &str,
177        auth: Option<Vec<Value>>,
178        sharable: bool,
179    ) -> Result<bool> {
180        let groups = self.get_groups().await?;
181        let group_data = groups
182            .iter()
183            .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(group))
184            .ok_or_else(|| {
185                crate::error::DVRIPError::Unknown(format!("Group '{}' not found", group))
186            })?;
187
188        let auth_list = auth.unwrap_or_else(|| {
189            group_data
190                .get("AuthorityList")
191                .and_then(|a| a.as_array())
192                .cloned()
193                .unwrap_or_default()
194        });
195
196        let data = json!({
197            "User": {
198                "AuthorityList": auth_list,
199                "Group": group,
200                "Memo": comment,
201                "Name": name,
202                "Password": sofia_hash(password),
203                "Reserved": false,
204                "Sharable": sharable,
205            }
206        });
207
208        let reply = self.set_command("User", data, None).await?;
209        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
210            return Ok(OK_CODES.contains(&(ret as u32)));
211        }
212        Ok(false)
213    }
214
215    async fn modify_user(
216        &mut self,
217        name: &str,
218        newname: Option<&str>,
219        comment: Option<&str>,
220        group: Option<&str>,
221        auth: Option<Vec<Value>>,
222        sharable: Option<bool>,
223    ) -> Result<bool> {
224        let users = self.get_users().await?;
225        let user = users
226            .iter()
227            .find(|u| u.get("Name").and_then(|n| n.as_str()) == Some(name))
228            .ok_or_else(|| {
229                crate::error::DVRIPError::Unknown(format!("User '{}' not found", name))
230            })?;
231
232        let mut auth_list = user
233            .get("AuthorityList")
234            .and_then(|a| a.as_array())
235            .cloned()
236            .unwrap_or_default();
237
238        if let Some(group_name) = group {
239            let groups = self.get_groups().await?;
240            if let Some(group_data) = groups
241                .iter()
242                .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(group_name))
243            {
244                auth_list = group_data
245                    .get("AuthorityList")
246                    .and_then(|a| a.as_array())
247                    .cloned()
248                    .unwrap_or_default();
249            }
250        }
251
252        let data = json!({
253            "User": {
254                "AuthorityList": auth.unwrap_or(auth_list),
255                "Group": group.or_else(|| user.get("Group").and_then(|g| g.as_str())).unwrap_or(""),
256                "Memo": comment.or_else(|| user.get("Memo").and_then(|m| m.as_str())).unwrap_or_default(),
257                "Name": newname.unwrap_or(name),
258                "Password": "",
259                "Reserved": user.get("Reserved").and_then(|r| r.as_bool()).unwrap_or(false),
260                "Sharable": sharable.or_else(|| user.get("Sharable").and_then(|s| s.as_bool())).unwrap_or(false),
261            },
262            "UserName": name,
263        });
264
265        let reply = self.set_command("ModifyUser", data, None).await?;
266        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
267            return Ok(OK_CODES.contains(&(ret as u32)));
268        }
269        Ok(false)
270    }
271
272    async fn delete_user(&mut self, name: &str) -> Result<bool> {
273        let session = self.session_id();
274        let data = json!({
275            "Name": name,
276            "SessionID": format!("0x{:08X}", session),
277        });
278
279        let reply = self.set_command("DelUser", data, None).await?;
280        if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
281            return Ok(OK_CODES.contains(&(ret as u32)));
282        }
283        Ok(false)
284    }
285}