Skip to main content

keepass_ng/db/types/
node.rs

1use crate::{
2    Result,
3    db::{Entry, Group, Times, iconid::IconId},
4};
5use std::collections::VecDeque;
6use uuid::Uuid;
7
8pub type NodePtr = std::rc::Rc<std::cell::RefCell<dyn Node>>;
9
10#[derive(Debug, Clone)]
11pub struct SerializableNodePtr {
12    node_ptr: NodePtr,
13}
14
15impl PartialEq for SerializableNodePtr {
16    fn eq(&self, other: &Self) -> bool {
17        node_is_equals_to(&self.node_ptr, &other.node_ptr)
18    }
19}
20
21impl Eq for SerializableNodePtr {}
22
23#[cfg(feature = "serialization")]
24impl serde::ser::Serialize for SerializableNodePtr {
25    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
26    where
27        S: serde::ser::Serializer,
28    {
29        let node = self.node_ptr.borrow();
30        if let Some(entry) = node.downcast_ref::<Entry>() {
31            return serde::Serialize::serialize(entry, serializer);
32        }
33        if let Some(group) = node.downcast_ref::<Group>() {
34            return serde::Serialize::serialize(group, serializer);
35        }
36        Err(serde::ser::Error::custom("unsupported node type"))
37    }
38}
39
40impl From<NodePtr> for SerializableNodePtr {
41    fn from(node: NodePtr) -> Self {
42        SerializableNodePtr { node_ptr: node }
43    }
44}
45
46impl From<&NodePtr> for SerializableNodePtr {
47    fn from(node: &NodePtr) -> Self {
48        SerializableNodePtr { node_ptr: node.clone() }
49    }
50}
51
52impl From<SerializableNodePtr> for NodePtr {
53    fn from(serializable: SerializableNodePtr) -> Self {
54        serializable.node_ptr
55    }
56}
57
58impl From<&SerializableNodePtr> for NodePtr {
59    fn from(serializable: &SerializableNodePtr) -> Self {
60        serializable.node_ptr.clone()
61    }
62}
63
64impl AsRef<NodePtr> for SerializableNodePtr {
65    fn as_ref(&self) -> &NodePtr {
66        &self.node_ptr
67    }
68}
69
70impl AsMut<NodePtr> for SerializableNodePtr {
71    fn as_mut(&mut self) -> &mut NodePtr {
72        &mut self.node_ptr
73    }
74}
75
76impl std::ops::Deref for SerializableNodePtr {
77    type Target = NodePtr;
78
79    fn deref(&self) -> &Self::Target {
80        &self.node_ptr
81    }
82}
83
84impl std::ops::DerefMut for SerializableNodePtr {
85    fn deref_mut(&mut self) -> &mut Self::Target {
86        &mut self.node_ptr
87    }
88}
89
90pub fn rc_refcell_node<T: Node>(e: T) -> NodePtr {
91    std::rc::Rc::new(std::cell::RefCell::new(e)) as NodePtr
92}
93
94/// Get a reference to a node if it is of the specified type
95/// and call the closure with the reference.
96/// Usage:
97/// ```no_run
98/// use keepass_ng::db::{with_node, Entry, Group, NodePtr, rc_refcell_node};
99///
100/// let node: NodePtr = rc_refcell_node(Group::new("group"));
101/// with_node::<Group, _, _>(&node, |group| {
102///     // do something with group
103/// });
104///
105/// with_node::<Entry, _, _>(&node, |entry| {
106///     // do something with entry
107/// });
108/// ```
109pub fn with_node<T, F, R>(node: &NodePtr, f: F) -> Option<R>
110where
111    T: 'static,
112    F: FnOnce(&T) -> R,
113{
114    node.borrow().downcast_ref::<T>().map(f)
115}
116
117/// Get a mutable reference to a node if it is of the specified type
118/// and call the closure with the mutable reference.
119/// Usage:
120/// ```no_run
121/// use keepass_ng::db::{with_node_mut, Entry, Group, NodePtr, rc_refcell_node};
122///
123/// let node: NodePtr = rc_refcell_node(Group::new("group"));
124/// with_node_mut::<Group, _, _>(&node, |group| {
125///     // do something with group
126/// });
127///
128/// with_node_mut::<Entry, _, _>(&node, |entry| {
129///     // do something with entry
130/// });
131/// ```
132pub fn with_node_mut<T, F, R>(node: &NodePtr, f: F) -> Option<R>
133where
134    T: 'static,
135    F: FnOnce(&mut T) -> R,
136{
137    node.borrow_mut().downcast_mut::<T>().map(f)
138}
139
140pub fn node_is_entry(entry: &NodePtr) -> bool {
141    with_node::<Entry, _, _>(entry, |_| true).unwrap_or(false)
142}
143
144pub fn node_is_group(group: &NodePtr) -> bool {
145    with_node::<Group, _, _>(group, |_| true).unwrap_or(false)
146}
147
148pub fn group_get_children(group: &NodePtr) -> Option<Vec<NodePtr>> {
149    with_node::<Group, _, _>(group, |g| g.get_children())
150}
151
152pub fn group_add_child(parent: &NodePtr, child: NodePtr, index: usize) -> Result<()> {
153    with_node_mut::<Group, _, _>(parent, |parent| {
154        parent.add_child(child, index);
155        Ok::<_, crate::Error>(())
156    })
157    .unwrap_or(Err("parent is not a group".into()))?;
158    Ok(())
159}
160
161pub fn group_remove_node_by_uuid(root: &NodePtr, uuid: Uuid) -> crate::Result<NodePtr> {
162    let root_uuid = root.borrow().get_uuid();
163    if root_uuid == uuid {
164        return Err("Cannot remove root node".into());
165    }
166
167    let node = search_node_by_uuid(root, uuid).ok_or("Node not found")?;
168    let parent_uuid = node.borrow().get_parent().ok_or("Node has no parent")?;
169    let err = format!("Parent \"{parent_uuid}\" not found");
170    let parent = search_node_by_uuid_with_specific_type::<Group>(root, parent_uuid).ok_or(err)?;
171    with_node_mut::<Group, _, _>(&parent, |parent| {
172        parent.children.retain(|c| c.borrow().get_uuid() != uuid);
173        Ok::<_, crate::Error>(())
174    })
175    .unwrap_or(Err(crate::Error::from("Not a group")))?;
176
177    Ok(node)
178}
179
180pub fn node_is_equals_to(node: &NodePtr, other: &NodePtr) -> bool {
181    if with_node::<Entry, _, _>(node, |e1| with_node::<Entry, _, _>(other, |e2| e1 == e2).unwrap_or(false)).unwrap_or(false) {
182        return true;
183    }
184    with_node::<Group, _, _>(node, |g1| with_node::<Group, _, _>(other, |g2| g1 == g2).unwrap_or(false)).unwrap_or(false)
185}
186
187pub fn search_node_by_uuid(root: &NodePtr, uuid: Uuid) -> Option<NodePtr> {
188    NodeIterator::new(root).find(|n| n.borrow().get_uuid() == uuid)
189}
190
191pub fn search_node_by_uuid_with_specific_type<'a, T>(root: &'a NodePtr, uuid: Uuid) -> Option<NodePtr>
192where
193    T: 'a + 'static,
194{
195    NodeIterator::new(root)
196        .filter(|n| with_node::<T, _, _>(n, |_| true).is_some())
197        .find(|n| n.borrow().get_uuid() == uuid)
198}
199
200pub trait Node: std::any::Any + std::fmt::Debug {
201    fn duplicate(&self) -> NodePtr;
202    fn get_uuid(&self) -> Uuid;
203    fn set_uuid(&mut self, uuid: Uuid);
204    fn get_title(&self) -> Option<&str>;
205    fn set_title(&mut self, title: Option<&str>);
206    fn get_notes(&self) -> Option<&str>;
207    fn set_notes(&mut self, notes: Option<&str>);
208    fn get_icon_id(&self) -> Option<IconId>;
209    fn set_icon_id(&mut self, icon_id: Option<IconId>);
210    fn get_custom_icon_uuid(&self) -> Option<Uuid>;
211
212    /// Get a timestamp field by name
213    ///
214    /// Returning the `NaiveDateTime` which does not include timezone
215    /// or UTC offset because `KeePass` clients typically store timestamps
216    /// relative to the local time on the machine writing the data without
217    /// including accurate UTC offset or timezone information.
218    fn get_times(&self) -> &Times;
219    fn get_times_mut(&mut self) -> &mut Times;
220
221    fn get_parent(&self) -> Option<Uuid>;
222    fn set_parent(&mut self, parent: Option<Uuid>);
223}
224
225impl dyn Node {
226    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
227        (self as &dyn std::any::Any).downcast_ref()
228    }
229
230    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
231        (self as &mut dyn std::any::Any).downcast_mut()
232    }
233}
234
235pub struct NodeIterator {
236    queue: VecDeque<NodePtr>,
237}
238
239impl NodeIterator {
240    pub fn new(root: &NodePtr) -> Self {
241        let mut queue = VecDeque::new();
242        queue.push_back(root.clone());
243        Self { queue }
244    }
245}
246
247impl Iterator for NodeIterator {
248    type Item = NodePtr;
249
250    fn next(&mut self) -> Option<Self::Item> {
251        let next = self.queue.pop_front()?;
252        if let Some(children) = group_get_children(&next) {
253            self.queue.extend(children);
254        }
255        Some(next)
256    }
257}