main.rs (7057B)
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 use log::{debug}; 40 41 //use ureq::{Agent, AgentBuilder}; 42 use ureq::AgentBuilder; 43 44 use clap::{ 45 App, 46 Arg, 47 }; 48 49 use xdg_home::home_dir; 50 51 use sequoia_openpgp::packet::prelude::*; 52 use sequoia_openpgp::cert::prelude::CertParser; 53 use sequoia_openpgp::serialize::Serialize; 54 use sequoia_openpgp::parse::Parse; 55 use sequoia_openpgp::parse::PacketParser; 56 use sequoia_openpgp::policy::StandardPolicy; 57 use sequoia_openpgp::packet::Key; 58 use sequoia_openpgp::packet::key::SecretParts; 59 use sequoia_openpgp::packet::key::PublicParts; 60 //use sequoia_openpgp::packet::key::UnspecifiedRole; 61 use sequoia_openpgp::packet::key::PrimaryRole; 62 use sequoia_openpgp::serialize::stream::Message; 63 use sequoia_openpgp::serialize::stream::Signer; 64 //use sequoia_openpgp::serialize::stream::LiteralWriter; 65 66 //use base64::encode; 67 68 use wala::record::{ResourceKey}; 69 use wala::auth::{AuthResult}; 70 71 72 #[doc(hidden)] 73 fn main() { 74 env_logger::init(); 75 76 let mut o = App::new("wala_send"); 77 o = o.version("0.1.0"); 78 o = o.author("Louis Holbrook <dev@holbrook.no>"); 79 80 o = o.arg(Arg::with_name("DATA") 81 .required(true) 82 ); 83 84 o = o.arg(Arg::with_name("url") 85 .short("u") 86 .long("url") 87 .takes_value(true) 88 .required(true) 89 ); 90 91 o = o.arg(Arg::with_name("ref_id") 92 .short("i") 93 .long("id") 94 .takes_value(true) 95 .multiple(true) 96 .number_of_values(1) 97 ); 98 99 o = o.arg(Arg::with_name("key") 100 .short("k") 101 .long("key") 102 .takes_value(true) 103 ); 104 105 106 let args = o.get_matches(); 107 108 let mut d: Vec<u8> = vec!(); 109 let mut nv = String::from("0"); 110 111 match args.values_of("ref_id") { 112 Some(vs) => { 113 for mut v in vs { 114 if v.len() < 2 { 115 continue; 116 } 117 if &v[..2] == "0x" { 118 v = &v[2..]; 119 if v.len() % 2 > 0 { 120 nv.push_str(v); 121 v = nv.as_ref(); 122 } 123 debug!("hex input {:?}", &v); 124 let mut r = hex::decode(v).unwrap(); 125 d.append(&mut r); 126 } else { 127 d.append(&mut v.as_bytes().to_vec()); 128 } 129 } 130 }, 131 None => {}, 132 } 133 134 let data = args.value_of("DATA").unwrap(); 135 136 //let mut auth: Option<AuthResult> = None; 137 //let auth: Option<AuthResult> = None; 138 139 let url_src = args.value_of("url").unwrap(); 140 let mut url = Url::parse(url_src).unwrap(); 141 142 //let have_auth = false; 143 let mut rk = ResourceKey { 144 v: Vec::new(), 145 }; 146 let mut auth_data = AuthResult { 147 identity: Vec::new(), 148 error: false, 149 }; 150 151 match args.value_of("key") { 152 Some(mut v) => { 153 if v.len() > 1 { 154 if &v[..2] == "0x" { 155 v = &v[2..]; 156 } 157 } 158 if v.len() % 2 > 0 { 159 nv.push_str(v); 160 v = nv.as_ref(); 161 } 162 auth_data.identity = hex::decode(&v).unwrap(); 163 rk.v = d.clone(); 164 let url_postfix = rk.pointer_for(&auth_data); 165 let url_postfix_hex = hex::encode(url_postfix); 166 url = url.join(&url_postfix_hex).unwrap(); 167 }, 168 None => {}, 169 } 170 171 let mut sk: Option<Key<SecretParts, PrimaryRole>> = None; 172 let p = StandardPolicy::new(); 173 if rk.v.len() > 0 { 174 let fp_stem = home_dir().unwrap(); 175 let fp = fp_stem.join(".gnupg/secring.gpg"); 176 let pp = PacketParser::from_file(fp).unwrap(); 177 178 // find a way to stop iter when key found 179 for v in CertParser::from(pp) { 180 match v { 181 Ok(r) => { 182 for k in r.keys() 183 .with_policy(&p, None) 184 .alive() 185 .revoked(false) 186 .for_signing() 187 .secret() 188 .map(|kk| kk.key()) { 189 if k.fingerprint().as_bytes() == auth_data.identity { 190 sk = Some(k.clone().role_into_primary()); 191 } 192 } 193 194 }, 195 Err(e) => { 196 panic!("keyparse fail: {:?}", e); 197 } 198 }; 199 } 200 } 201 202 let mut sig_bsf = String::new(); 203 let mut pubkey_bsf = String::new(); 204 205 match sk { 206 Some(mut k) => { 207 let mut sig_sink = vec!(); 208 let mut pubkey_sink = vec!(); 209 210 if k.secret().is_encrypted() { 211 let pwd = rpassword::prompt_password("Key passphrase: ").unwrap(); 212 let algo = k.pk_algo(); 213 _ = k.secret_mut() 214 .decrypt_in_place(algo, &pwd.into()); 215 } 216 217 //let mut sig_msg = Message::new(&mut sig_sink); 218 let sig_msg = Message::new(&mut sig_sink); 219 220 let kp = k.clone().into_keypair().unwrap(); 221 let pk: Key<PublicParts, PrimaryRole> = kp.public().clone().role_into_primary(); 222 let mut signer = Signer::new(sig_msg, kp) 223 .detached() 224 .build() 225 .unwrap(); 226 _ = signer.write_all(&data.as_bytes()); 227 _ = signer.finalize(); 228 229 _ = Packet::from(pk).serialize(&mut pubkey_sink); 230 231 sig_bsf = base64::encode(sig_sink); 232 pubkey_bsf = base64::encode(pubkey_sink); 233 }, 234 None => {}, 235 }; 236 237 let ua = AgentBuilder::new().build(); 238 let mut rq = ua.put(url.as_str()); 239 240 if sig_bsf.len() > 0 { 241 let hdr_val = format!("PUBSIG pgp:{}:{}", pubkey_bsf, sig_bsf); 242 rq = rq.set("Authorization", hdr_val.as_str()); 243 } 244 let rs = rq.send_bytes(&data.as_bytes()); 245 246 println!("{}", rs.unwrap().into_string().unwrap()); 247 }