From 209a0ae2a33818854c5350837f617eeee1a390cb Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Fri, 15 Jan 2021 01:05:15 -0500 Subject: [PATCH] Version 2.0.0, with added XEP-0027 PGP support --- Cargo.lock | 53 +++++++++++++++++++++++++-------------------- Cargo.toml | 3 ++- src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43d9197..f8da4f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,11 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + [[package]] name = "arrayref" version = "0.3.6" @@ -262,9 +268,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309f13e3f4be6d5917178c84db67c0b9a09177ac16d4f9a7313a767a68adaa77" +checksum = "90fa4cc29d25b0687b8570b0da86eac698dcb525110ad8b938fe6712baa711ec" dependencies = [ "futures-channel", "futures-core", @@ -277,9 +283,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3b03bd32f6ec7885edeb99acd1e47e20e34fd4dfd3c6deed6fcac8a9d28f6a" +checksum = "31ebc390c6913de330e418add60e1a7e5af4cb5ec600d19111b339cafcdcc027" dependencies = [ "futures-core", "futures-sink", @@ -287,15 +293,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed8aeae2b6ab243ebabe6f54cd4cf53054d98883d5d326128af7d57a9ca5cd3d" +checksum = "089bd0baf024d3216916546338fffe4fc8dfffdd901e33c278abb091e0d52111" [[package]] name = "futures-executor" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7836b36b7533d16fd5937311d98ba8965ab81030de8b0024c299dd5d51fb9b" +checksum = "d0cb59f15119671c94cd9cc543dc9a50b8d5edc468b4ff5f0bb8567f66c6b48a" dependencies = [ "futures-core", "futures-task", @@ -304,15 +310,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41234e71d5e8ca73d01563974ef6f50e516d71e18f1a2f1184742e31f5d469f" +checksum = "3868967e4e5ab86614e2176c99949eeef6cbcacaee737765f6ae693988273997" [[package]] name = "futures-macro" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3520e0eb4e704e88d771b92d51273ee212997f0d8282f17f5d8ff1cb39104e42" +checksum = "95778720c3ee3c179cd0d8fd5a0f9b40aa7d745c080f86a8f8bed33c4fd89758" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -322,24 +328,24 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72d188479368953c6c8c7140e40d7a4401674ab3b98a41e60e515d6cbdbe5de" +checksum = "d4e0f6be0ec0357772fd58fb751958dd600bd0b3edfd429e77793e4282831360" [[package]] name = "futures-task" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08944cea9021170d383287169859c0ca8147d9ec285978393109954448f33cc7" +checksum = "868090f28a925db6cb7462938c51d807546e298fb314088239f0e52fb4338b96" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd206efbe2ca683b2ce138ccdf61e1b0a63f5816dcedc9d8654c500ba0cea6" +checksum = "cad5e82786df758d407932aded1235e24d8e2eb438b6adafd37930c2462fb5d1" dependencies = [ "futures-channel", "futures-core", @@ -855,9 +861,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" @@ -1128,8 +1134,9 @@ dependencies = [ [[package]] name = "sendxmpp" -version = "1.0.1" +version = "2.0.0" dependencies = [ + "anyhow", "die", "dirs", "gumdrop", @@ -1354,9 +1361,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d258221f566b6c803c7b4714abadc080172b272090cdc5e244a6d4dd13c3a6bd" +checksum = "0ca04cec6ff2474c638057b65798f60ac183e5e79d3448bb7163d36a39cff6ec" dependencies = [ "autocfg", "libc", diff --git a/Cargo.toml b/Cargo.toml index 13ce652..9eebb70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sendxmpp" -version = "1.0.1" +version = "2.0.0" authors = ["moparisthebest "] description = "Send XMPP messages from the command line." @@ -25,3 +25,4 @@ tokio-xmpp = "3.0.0" tokio = { version = "1", features = ["net", "rt", "rt-multi-thread", "macros"] } xmpp-parsers = "0.18" die = "0.2.0" +anyhow = "1.0" diff --git a/src/main.rs b/src/main.rs index d0d4e6d..8bd3256 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::env::args; use std::fs::File; -use std::io::{stdin, Read}; +use std::io::{stdin, Read, Write}; use std::iter::Iterator; use std::path::Path; @@ -11,6 +11,9 @@ use serde_derive::Deserialize; use tokio_xmpp::SimpleClient as Client; use xmpp_parsers::message::{Body, Message}; use xmpp_parsers::{Element, Jid}; +use std::process::{Command, Stdio}; + +use anyhow::{Result, bail, anyhow}; #[derive(Deserialize)] struct Config { @@ -111,8 +114,27 @@ async fn main() { let mut client = Client::new(&cfg.jid, &cfg.password).await.die("could not connect to xmpp server"); for recipient in recipients { - let reply = make_reply(recipient.clone(), &data); - client.send_stanza(reply).await.unwrap(); + let reply = if opts.force_pgp || opts.attempt_pgp { + let encrypted = gpg_encrypt(recipient.clone(), &data); + if encrypted.is_err() { + if opts.force_pgp { + die!("pgp encryption to jid '{}' failed!", recipient); + } else { + make_reply(recipient.clone(), &data) + } + } else { + let encrypted = encrypted.unwrap(); + let encrypted = encrypted.trim(); + let mut reply = make_reply(recipient.clone(), "pgp"); + let mut x = Element::bare("x", "jabber:x:encrypted"); + x.append_text_node(encrypted); + reply.append_child(x); + reply + } + } else { + make_reply(recipient.clone(), &data) + }; + client.send_stanza(reply).await.die("sending message failed"); } // Close client connection @@ -125,3 +147,37 @@ fn make_reply(to: Jid, body: &str) -> Element { message.bodies.insert(String::new(), Body(body.to_owned())); message.into() } + +fn gpg_encrypt(to: Jid, body: &str) -> Result { + let to: String = std::convert::From::from(to); + let mut gpg_cmd = Command::new("gpg") + .arg("--encrypt") + .arg("--armor") + .arg("-r") + .arg(to) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + { + let stdin = gpg_cmd.stdin.as_mut().ok_or_else(|| anyhow!("no gpg stdin"))?; + stdin.write_all(body.as_bytes())?; + } + + let output = gpg_cmd.wait_with_output()?; + + if !output.status.success() { + bail!("gpg exited with non-zero status code"); + } + + let output = output.stdout; + + if output.len() < (28+26+10) { // 10 is just a... fudge factor + bail!("length {} returned by gpg too short to be valid", output.len()); + } + + let start = 28; // length of -----BEGIN PGP MESSAGE----- is 28 + let end = output.len() - 26; // length of -----END PGP MESSAGE----- is 26 + + Ok(String::from_utf8((&output[start..end]).to_vec())?) +}