tap_node/validation/
uniqueness_validator.rs1use super::{MessageValidator, ValidationResult};
4use crate::storage::Storage;
5use async_trait::async_trait;
6use std::sync::Arc;
7use tap_msg::didcomm::PlainMessage;
8
9pub struct UniquenessValidator {
14 storage: Arc<Storage>,
15}
16
17impl UniquenessValidator {
18 pub fn new(storage: Arc<Storage>) -> Self {
20 Self { storage }
21 }
22}
23
24#[async_trait]
25impl MessageValidator for UniquenessValidator {
26 async fn validate(&self, message: &PlainMessage) -> ValidationResult {
27 match self.storage.get_message_by_id(&message.id).await {
29 Ok(Some(_)) => {
30 ValidationResult::Reject(format!(
32 "Duplicate message: message with ID {} already processed",
33 message.id
34 ))
35 }
36 Ok(None) => {
37 ValidationResult::Accept
39 }
40 Err(e) => {
41 ValidationResult::Reject(format!("Unable to verify message uniqueness: {}", e))
43 }
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::storage::MessageDirection;
52 use tempfile::tempdir;
53
54 #[tokio::test]
55 async fn test_unique_message() {
56 let dir = tempdir().unwrap();
57 let storage = Arc::new(
58 Storage::new(Some(dir.path().join("test.db")))
59 .await
60 .unwrap(),
61 );
62 let validator = UniquenessValidator::new(storage);
63
64 let message = PlainMessage::new(
65 "test_msg_1".to_string(),
66 "test_type".to_string(),
67 serde_json::json!({}),
68 "did:example:sender".to_string(),
69 )
70 .with_recipient("did:example:receiver");
71
72 match validator.validate(&message).await {
73 ValidationResult::Accept => {} ValidationResult::Reject(reason) => panic!("Expected accept, got reject: {}", reason),
75 }
76 }
77
78 #[tokio::test]
79 async fn test_duplicate_message() {
80 let dir = tempdir().unwrap();
81 let storage = Arc::new(
82 Storage::new(Some(dir.path().join("test.db")))
83 .await
84 .unwrap(),
85 );
86 let validator = UniquenessValidator::new(storage.clone());
87
88 let message = PlainMessage::new(
89 "test_msg_1".to_string(),
90 "test_type".to_string(),
91 serde_json::json!({}),
92 "did:example:sender".to_string(),
93 )
94 .with_recipient("did:example:receiver");
95
96 storage
98 .log_message(&message, MessageDirection::Incoming)
99 .await
100 .unwrap();
101
102 match validator.validate(&message).await {
104 ValidationResult::Accept => panic!("Expected reject, got accept"),
105 ValidationResult::Reject(reason) => {
106 assert!(reason.contains("Duplicate message"));
107 assert!(reason.contains(&message.id));
108 }
109 }
110 }
111}