Skip to main content

relay_actions/actions/
messages.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    actions::Action, cache::CacheManager, sign::sign_request, sinks::progress::ProgressSink,
5    storage::Storage,
6};
7use relay_lib::prelude::{Address, InboxId, MetaEnvelope, PrivateEnvelope, e2e};
8
9#[derive(Serialize)]
10struct InboxMessagesReq {
11    pub inbox: Option<InboxId>,
12    pub start: Option<u32>,
13    pub amount: Option<u32>,
14}
15
16#[derive(Deserialize)]
17struct InboxMessagesResp {
18    pub messages: Vec<MetaEnvelope>,
19}
20
21pub struct Messages {
22    pub address: Address,
23    pub contents: bool,
24}
25
26impl Action for Messages {
27    type Output = Vec<(MetaEnvelope, PrivateEnvelope)>;
28
29    fn execute(
30        &self,
31        storage: &mut Storage,
32        cache: &mut CacheManager,
33        progress: &mut dyn ProgressSink,
34    ) -> Self::Output {
35        let identity = storage
36            .root
37            .get_identity(&self.address)
38            .unwrap_or_else(|| {
39                progress.abort(&format!("No identity found for address `{}`", self.address));
40            })
41            .clone();
42
43        progress.step("Fetching records", "Fetched records");
44        let agent_record = cache
45            .records
46            .agent(&mut cache.agents, self.address.agent())
47            .unwrap_or_else(|e| {
48                progress.error(&format!("{:?}", e));
49                progress.abort("Failed to fetch agent record");
50            });
51
52        progress.step("Fetching messages", "Fetched messages");
53        let request = sign_request(
54            &self.address.canonical(),
55            InboxMessagesReq {
56                inbox: self.address.inbox().cloned(),
57                start: None,
58                amount: None,
59            },
60            &agent_record,
61            &identity.signing_key(),
62        )
63        .unwrap_or_else(|e| {
64            progress.error(&format!("{:?}", e));
65            progress.abort("Failed to sign messages request");
66        });
67
68        let resp = reqwest::blocking::Client::new()
69            .get(
70                cache
71                    .agents
72                    .url(self.address.agent())
73                    .unwrap_or_else(|e| {
74                        progress.error(&format!("{:?}", e));
75                        progress.abort("Failed to fetch Agent information");
76                    })
77                    .join("/inbox/messages")
78                    .unwrap_or_else(|e| {
79                        progress.error(&format!("{:?}", e));
80                        progress.abort("Failed to construct inbox messages URL");
81                    }),
82            )
83            .json(&request)
84            .send()
85            .unwrap_or_else(|e| {
86                progress.error(&format!("{:?}", e));
87                progress.abort("Failed to send messages request");
88            });
89
90        if resp.status().as_u16() == 404 {
91            progress.abort("Inbox not found on the Agent");
92        }
93
94        if !resp.status().is_success() {
95            progress.abort(&format!(
96                "Failed to list messages. HTTP {}",
97                resp.status().as_u16()
98            ));
99        }
100
101        progress.step("Processing response", "Processed response");
102        let mut response = resp.json::<InboxMessagesResp>().unwrap_or_else(|e| {
103            progress.error(&format!("{:?}", e));
104            progress.abort("Failed to parse messages response");
105        });
106
107        progress.step("Decrypting messages", "Decrypted messages");
108        response.messages.sort_by_key(|m| m.timestamp);
109        let messages = response
110            .messages
111            .iter()
112            .map(|meta| {
113                let payload = e2e::decrypt(
114                    &identity.static_secret(),
115                    &meta.crypto,
116                    &meta.payload.payload,
117                    &[],
118                )
119                .unwrap_or_else(|e| {
120                    progress.error(&format!("{:?}", e));
121                    progress.abort(&format!("Failed to decrypt message with GID {}", meta.gid));
122                });
123
124                let private =
125                    serde_json::from_slice::<PrivateEnvelope>(&payload).unwrap_or_else(|e| {
126                        progress.error(&format!("{:?}", e));
127                        progress.abort(&format!(
128                            "Failed to parse private envelope for message with GID {}",
129                            meta.gid
130                        ));
131                    });
132
133                (meta.clone(), private)
134            })
135            .collect::<Vec<_>>();
136
137        progress.done();
138        messages
139    }
140}