relay_actions/actions/
read.rs1use 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
9pub struct Read {
10 pub address: Address,
11 pub gid: String,
12 pub silent: bool,
13 pub raw: bool,
14}
15
16impl Action for Read {
17 type Output = (MetaEnvelope, PrivateEnvelope);
18
19 fn execute(
20 &self,
21 storage: &mut Storage,
22 cache: &mut CacheManager,
23 progress: &mut dyn ProgressSink,
24 ) -> Self::Output {
25 let identity = storage
26 .root
27 .get_identity(&self.address)
28 .unwrap_or_else(|| {
29 progress.abort(&format!("No identity found for address `{}`", self.address));
30 })
31 .clone();
32
33 progress.step("Fetching records", "Fetched records");
34 let agent_record = cache
35 .records
36 .agent(&mut cache.agents, self.address.agent())
37 .unwrap_or_else(|e| {
38 progress.error(&format!("{:#?}", e));
39 progress.abort("Failed to fetch agent record");
40 });
41
42 progress.step("Fetching message", "Fetched message");
43 let request = sign_request(
44 &self.address.canonical(),
45 InboxSingleReq {
46 inbox: self.address.inbox().cloned(),
47 gid: self.gid.clone(),
48 },
49 &agent_record,
50 &identity.signing_key(),
51 )
52 .unwrap_or_else(|e| {
53 progress.error(&format!("{:#?}", e));
54 progress.abort("Failed to sign messages request");
55 });
56
57 let resp = reqwest::blocking::Client::new()
58 .get(
59 cache
60 .agents
61 .url(self.address.agent())
62 .unwrap_or_else(|e| {
63 progress.error(&format!("{:#?}", e));
64 progress.abort("failed to fetch agent information");
65 })
66 .join("/inbox/single")
67 .unwrap_or_else(|e| {
68 progress.error(&format!("{:#?}", e));
69 progress.abort("Failed to construct inbox single URL");
70 }),
71 )
72 .json(&request)
73 .send()
74 .unwrap_or_else(|e| {
75 progress.error(&format!("{:#?}", e));
76 progress.abort("Failed to send inbox single message request");
77 });
78
79 if resp.status().as_u16() == 404 {
80 progress.abort("Message not found");
81 }
82 if !resp.status().is_success() {
83 progress.abort(&format!(
84 "Failed to fetch message. HTTP {}",
85 resp.status().as_u16()
86 ));
87 }
88 let response = resp.json::<InboxSingleResp>().unwrap_or_else(|e| {
89 progress.error(&format!("{:#?}", e));
90 progress.abort("Failed to parse inbox single message response");
91 });
92 let meta = response.message.clone();
93
94 progress.step("Decrypting message", "Decrypted message");
95 let payload = e2e::decrypt(
96 &identity.static_secret(),
97 &meta.crypto,
98 &meta.payload.payload,
99 &[],
100 )
101 .unwrap_or_else(|e| {
102 progress.error(&format!("{:#?}", e));
103 progress.abort("Failed to decrypt message")
104 });
105
106 progress.step("Parsing message", "Parsed message");
107 let private = serde_json::from_slice::<PrivateEnvelope>(&payload).unwrap_or_else(|e| {
108 progress.error(&format!("{:#?}", e));
109 progress.abort("Failed to parse message payload")
110 });
111
112 progress.step("Displaying message", "Displayed message");
113 if private.content_type != "plain/text" && !self.raw {
114 progress.abort(&format!(
115 "Unsupported content type: {}. Pass `--raw` to see dump content.",
116 private.content_type
117 ));
118 }
119
120 progress.done();
121 (meta, private)
122 }
123}
124
125#[derive(Serialize)]
126struct InboxSingleReq {
127 pub inbox: Option<InboxId>,
128 pub gid: String,
129}
130
131#[derive(Deserialize)]
132struct InboxSingleResp {
133 pub message: MetaEnvelope,
134}