1use base64::Engine;
2use clap::{Parser, Subcommand};
3use proteus_wasm::internal::message::SessionTag;
4use proteus_wasm::internal::util::fmt_hex;
5use proteus_wasm::keys::{PreKeyBundle, Signature};
6use proteus_wasm::message::{CipherMessage, Envelope, Message, PreKeyMessage};
7use std::ops::Deref;
8
9#[derive(Debug)]
10#[allow(dead_code)]
11struct ProteusPreKeyBundle {
12 pub version: u8,
13 pub prekey_id: u16,
14 pub public_key: String,
15 pub identity_key: String,
16 pub signature: Option<Signature>,
17}
18
19impl From<PreKeyBundle> for ProteusPreKeyBundle {
20 fn from(bundle: PreKeyBundle) -> Self {
21 Self {
22 version: bundle.version,
23 prekey_id: bundle.prekey_id.value(),
24 public_key: bundle.public_key.fingerprint(),
25 identity_key: bundle.identity_key.fingerprint(),
26 signature: bundle.signature,
27 }
28 }
29}
30
31#[derive(Debug)]
32#[allow(dead_code)]
33struct ProteusEnvelope {
34 version: u16,
35 mac: String,
36 message: ProteusMessage,
37}
38
39#[derive(Debug)]
40#[allow(dead_code)]
41enum ProteusMessage {
42 Plain(ProteusCipherMessage),
43 Keyed(ProteusPrekeyMessage),
44}
45
46#[derive(Debug)]
47#[allow(dead_code)]
48struct ProteusPrekeyMessage {
49 prekey_id: u16,
50 base_key: String,
51 identity_key: String,
52 message: ProteusCipherMessage,
53}
54
55#[derive(Debug)]
56#[allow(dead_code)]
57struct ProteusCipherMessage {
58 pub session_tag: SessionTag,
59 pub counter: u32,
60 pub prev_counter: u32,
61 pub ratchet_key: String,
62 pub cipher_text: String,
63}
64
65impl From<Envelope<'_>> for ProteusEnvelope {
66 fn from(envelope: Envelope) -> Self {
67 Self {
68 version: envelope.version(),
69 mac: fmt_hex(&envelope.mac().clone().into_bytes()),
70 message: envelope.message().into(),
71 }
72 }
73}
74
75impl From<&Message<'_>> for ProteusMessage {
76 fn from(message: &Message) -> Self {
77 match message {
78 Message::Plain(plain) => ProteusMessage::Plain(plain.deref().into()),
79 Message::Keyed(keyed) => ProteusMessage::Keyed(keyed.deref().into()),
80 }
81 }
82}
83
84impl From<&PreKeyMessage<'_>> for ProteusPrekeyMessage {
85 fn from(message: &PreKeyMessage) -> Self {
86 Self {
87 prekey_id: message.prekey_id.value(),
88 base_key: message.base_key.fingerprint(),
89 identity_key: message.identity_key.fingerprint(),
90 message: (&message.message).into(),
91 }
92 }
93}
94
95impl From<&CipherMessage<'_>> for ProteusCipherMessage {
96 fn from(message: &CipherMessage) -> Self {
97 Self {
98 session_tag: message.session_tag,
99 counter: message.counter.value(),
100 prev_counter: message.prev_counter.value(),
101 ratchet_key: message.ratchet_key.fingerprint(),
102 cipher_text: base64::prelude::BASE64_STANDARD.encode(message.cipher_text.clone()),
103 }
104 }
105}
106
107#[derive(Parser, Debug)]
109#[clap(name = "decode", version)]
110pub struct App {
111 #[clap(subcommand)]
112 command: Command,
113}
114
115#[derive(Debug, Subcommand)]
116enum Command {
117 PrekeyBundle { bundle: String },
119 ProteusMessage {
121 message: String,
123 },
124}
125
126fn main() -> Result<(), Box<dyn std::error::Error>> {
127 let app = App::parse();
128 match app.command {
129 Command::PrekeyBundle { bundle } => {
130 let bytes = base64::prelude::BASE64_STANDARD.decode(bundle)?;
131 let bundle = PreKeyBundle::deserialise(&bytes)?;
132 println!("{:#?}", ProteusPreKeyBundle::from(bundle));
133 Ok(())
134 }
135 Command::ProteusMessage { message } => {
136 let bytes = base64::prelude::BASE64_STANDARD.decode(message)?;
137 let message = Envelope::deserialise(&bytes)?;
138 println!("{:#?}", ProteusEnvelope::from(message));
139 Ok(())
140 }
141 }
142}