decode/
main.rs

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/// Utility for decoding various wire formats for mls and proteus
108#[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    /// Decode a proteus prekey bundle
118    PrekeyBundle { bundle: String },
119    /// Decode a proteus message
120    ProteusMessage {
121        /// Base64 encoded proteus message
122        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}