main.rs (6896B)
1 #![crate_name = "wala_send"] 2 3 //! This is a convenience tool to upload content to wala under mutable references. 4 //! 5 //! It is still in a very unsophisticated state, and has two notable limitations: 6 //! 7 //! - Content to upload must be provided as a literal argument 8 //! - It only uses gnupg private keys stored in the keyring in `~/.gnupg/`. 9 //! 10 //! ## Examples 11 //! 12 //! Assuming that `wala` is running on default host and port - localhost:8000. 13 //! 14 //! ### Upload content to a content address 15 //! 16 //! ``` ignore, 17 //! wala_send -u http://localhost:8000 foo 18 //! ``` 19 //! 20 //! ### Upload content to a mutable reference 21 //! 22 //! ``` ignore, 23 //! wala_send -u http://localhost:8000 -k <pgp_fingerprint> -i <keyword> foo 24 //! ``` 25 //! 26 //! For more details on what funcionality [wala](wala) provides, please consult the 27 //! [library crate documentation](wala). 28 29 use std::env::home_dir; 30 use std::io::stdout; 31 use std::io::copy; 32 use std::io::Write; 33 34 use env_logger; 35 36 use url::Url; 37 38 use log::{info, debug}; 39 40 use ureq::{Agent, AgentBuilder}; 41 42 use clap::{ 43 App, 44 Arg, 45 }; 46 47 use sequoia_openpgp::packet::prelude::*; 48 use sequoia_openpgp::cert::prelude::CertParser; 49 use sequoia_openpgp::serialize::Serialize; 50 use sequoia_openpgp::parse::Parse; 51 use sequoia_openpgp::parse::PacketParser; 52 use sequoia_openpgp::policy::StandardPolicy; 53 use sequoia_openpgp::packet::Key; 54 use sequoia_openpgp::packet::key::SecretParts; 55 use sequoia_openpgp::packet::key::PublicParts; 56 use sequoia_openpgp::packet::key::UnspecifiedRole; 57 use sequoia_openpgp::packet::key::PrimaryRole; 58 use sequoia_openpgp::serialize::stream::Message; 59 use sequoia_openpgp::serialize::stream::Signer; 60 use sequoia_openpgp::serialize::stream::LiteralWriter; 61 62 use base64::encode; 63 64 use wala::record::{ResourceKey}; 65 use wala::auth::{AuthResult}; 66 67 68 #[doc(hidden)] 69 fn main() { 70 env_logger::init(); 71 72 let mut o = App::new("wala_send"); 73 o = o.version("0.1.0"); 74 o = o.author("Louis Holbrook <dev@holbrook.no>"); 75 76 o = o.arg(Arg::with_name("DATA") 77 .required(true) 78 ); 79 80 o = o.arg(Arg::with_name("url") 81 .short("u") 82 .long("url") 83 .takes_value(true) 84 .required(true) 85 ); 86 87 o = o.arg(Arg::with_name("ref_id") 88 .short("i") 89 .long("id") 90 .takes_value(true) 91 .multiple(true) 92 .number_of_values(1) 93 ); 94 95 o = o.arg(Arg::with_name("key") 96 .short("k") 97 .long("key") 98 .takes_value(true) 99 ); 100 101 102 let args = o.get_matches(); 103 104 let mut d: Vec<u8> = vec!(); 105 let mut nv = String::from("0"); 106 107 match args.values_of("ref_id") { 108 Some(vs) => { 109 for mut v in vs { 110 if v.len() < 2 { 111 continue; 112 } 113 if &v[..2] == "0x" { 114 v = &v[2..]; 115 if v.len() % 2 > 0 { 116 nv.push_str(v); 117 v = nv.as_ref(); 118 } 119 debug!("hex input {:?}", &v); 120 let mut r = hex::decode(v).unwrap(); 121 d.append(&mut r); 122 } else { 123 d.append(&mut v.as_bytes().to_vec()); 124 } 125 } 126 }, 127 None => {}, 128 } 129 130 let data = args.value_of("DATA").unwrap(); 131 132 let mut auth: Option<AuthResult> = None; 133 134 let url_src = args.value_of("url").unwrap(); 135 let mut url = Url::parse(url_src).unwrap(); 136 137 let mut have_auth = false; 138 let mut rk = ResourceKey { 139 v: Vec::new(), 140 }; 141 let mut auth_data = AuthResult { 142 identity: Vec::new(), 143 error: false, 144 }; 145 146 match args.value_of("key") { 147 Some(mut v) => { 148 if v.len() > 1 { 149 if &v[..2] == "0x" { 150 v = &v[2..]; 151 } 152 } 153 if v.len() % 2 > 0 { 154 nv.push_str(v); 155 v = nv.as_ref(); 156 } 157 auth_data.identity = hex::decode(&v).unwrap(); 158 rk.v = d.clone(); 159 let url_postfix = rk.pointer_for(&auth_data); 160 let url_postfix_hex = hex::encode(url_postfix); 161 url = url.join(&url_postfix_hex).unwrap(); 162 }, 163 None => {}, 164 } 165 166 let mut sk: Option<Key<SecretParts, PrimaryRole>> = None; 167 let p = StandardPolicy::new(); 168 if rk.v.len() > 0 { 169 let fp_stem = home_dir().unwrap(); 170 let fp = fp_stem.join(".gnupg/secring.gpg"); 171 let pp = PacketParser::from_file(fp).unwrap(); 172 173 // find a way to stop iter when key found 174 for v in CertParser::from(pp) { 175 match v { 176 Ok(r) => { 177 for k in r.keys() 178 .with_policy(&p, None) 179 .alive() 180 .revoked(false) 181 .for_signing() 182 .secret() 183 .map(|kk| kk.key()) { 184 if k.fingerprint().as_bytes() == auth_data.identity { 185 sk = Some(k.clone().role_into_primary()); 186 } 187 } 188 189 }, 190 Err(e) => { 191 panic!("keyparse fail: {:?}", e); 192 } 193 }; 194 } 195 } 196 197 let mut sig_bsf = String::new(); 198 let mut pubkey_bsf = String::new(); 199 200 match sk { 201 Some(mut k) => { 202 let mut sig_sink = vec!(); 203 let mut pubkey_sink = vec!(); 204 205 let mut pwd = String::new(); 206 if k.secret().is_encrypted() { 207 pwd = rpassword::prompt_password("Key passphrase: ").unwrap(); 208 let algo = k.pk_algo(); 209 k.secret_mut() 210 .decrypt_in_place(algo, &pwd.into()); 211 212 } 213 214 let mut sig_msg = Message::new(&mut sig_sink); 215 216 let kp = k.clone().into_keypair().unwrap(); 217 let pk: Key<PublicParts, PrimaryRole> = kp.public().clone().role_into_primary(); 218 let mut signer = Signer::new(sig_msg, kp) 219 .detached() 220 .build() 221 .unwrap(); 222 signer.write_all(&data.as_bytes()); 223 signer.finalize(); 224 225 Packet::from(pk).serialize(&mut pubkey_sink); 226 227 sig_bsf = base64::encode(sig_sink); 228 pubkey_bsf = base64::encode(pubkey_sink); 229 }, 230 None => {}, 231 }; 232 233 let ua = AgentBuilder::new().build(); 234 let mut rq = ua.put(url.as_str()); 235 236 if sig_bsf.len() > 0 { 237 let hdr_val = format!("PUBSIG pgp:{}:{}", pubkey_bsf, sig_bsf); 238 rq = rq.set("Authorization", hdr_val.as_str()); 239 } 240 let rs = rq.send_bytes(&data.as_bytes()); 241 242 println!("{}", rs.unwrap().into_string().unwrap()); 243 }