decode/
main.rs

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