#![forbid(
exceeding_bitshifts, mutable_transmutes, no_mangle_const_items, unknown_crate_types, warnings
)]
#![deny(
bad_style, deprecated, improper_ctypes, missing_docs, non_shorthand_field_patterns,
overflowing_literals, plugin_as_library, private_no_mangle_fns, private_no_mangle_statics,
stable_features, unconditional_recursion, unknown_lints, unsafe_code, unused, unused_allocation,
unused_attributes, unused_comparisons, unused_features, unused_parens, while_true
)]
#![warn(
trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces,
unused_qualifications, unused_results
)]
#![allow(
box_pointers, missing_copy_implementations, missing_debug_implementations,
variant_size_differences
)]
#![cfg_attr(
feature = "cargo-clippy",
deny(clippy, unicode_not_nfc, wrong_pub_self_convention, option_unwrap_used)
)]
#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher, too_many_arguments, use_debug))]
#[macro_use]
extern crate clap;
extern crate futures;
extern crate maidsafe_utilities;
extern crate rand;
extern crate safe_app;
extern crate safe_authenticator;
#[macro_use]
extern crate safe_core;
extern crate tiny_keccak;
#[macro_use]
extern crate unwrap;
use clap::{App as ClapApp, Arg};
use futures::Future;
use rand::{thread_rng, Rng};
use safe_app::utils::seed;
use safe_app::{Action, App, Client, FutureExt, MutableData, PermissionSet, User, XorName};
use safe_authenticator::Authenticator;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::mpsc;
use std::time::UNIX_EPOCH;
use tiny_keccak::sha3_256;
const INVITE_TOKEN_SIZE: usize = 90;
const INVITE_TOKEN_TYPE_TAG: u64 = 8;
fn main() {
unwrap!(maidsafe_utilities::log::init(true));
let matches = ClapApp::new("gen_invites")
.about("Generate invites to the network")
.arg(
Arg::with_name("gen-seed")
.long("gen-seed")
.takes_value(true)
.help("Only generate a random seed of given size, writing into input file."),
)
.arg(
Arg::with_name("get-pk")
.long("get-pk")
.help("Only get the public sign key given the seed, don't do anything extra."),
)
.arg(
Arg::with_name("check-invite")
.long("check-invite")
.takes_value(true)
.help("Only check the status of the given invite (exists, consumed etc.)."),
)
.arg(
Arg::with_name("create")
.short("c")
.long("create")
.help("Create account using seed from input file. By default it will login."),
)
.arg(
Arg::with_name("num-invites")
.short("n")
.long("num-invites")
.takes_value(true)
.help("Number of invites to generate (will populate the Network too)."),
)
.get_matches();
if let Ok(size) = value_t!(matches, "gen-seed", usize) {
let mut input = unwrap!(File::create("./input"), "Unable to create input file");
let seed = generate_random_printable(size);
unwrap!(write!(input, "{}", seed));
return println!("----------- Done -----------");
}
let mut seed = String::with_capacity(100);
{
let mut input = unwrap!(File::open("./input"), "Unable to open input file");
let _ = unwrap!(input.read_to_string(&mut seed));
}
if matches.is_present("get-pk") {
let sign_pk = unwrap!(seed::sign_pk_from_seed(&seed));
return println!("Public Signing Key: {:?}", sign_pk.0);
}
if let Some(invite) = matches.value_of("check-invite") {
let invite = invite.to_string();
let app = unwrap!(App::unregistered(|| (), None,));
let (tx, rx) = mpsc::channel();
unwrap!(app.send(move |client, _| {
let id = XorName(sha3_256(invite.as_str().as_bytes()));
client
.get_mdata_version(id, INVITE_TOKEN_TYPE_TAG)
.then(move |res| -> Result<(), ()> {
match res {
Ok(version) => println!("Invite version: {}", version),
Err(e) => println!("Can't find invite: {:?}", e),
}
unwrap!(tx.send(()));
Ok(())
})
.map_err(|e| panic!("{:?}", e))
.into_box()
.into()
}));
unwrap!(rx.recv());
println!("----------- Done -----------");
return;
}
let output = {
let name = format!("./output-{}", unwrap!(UNIX_EPOCH.elapsed()).as_secs());
unwrap!(File::create(&name))
};
let create = matches.is_present("create");
let auth = unwrap!(if create {
println!("\nTrying to create an account using given seed from file...");
Authenticator::create_acc_with_seed(seed.as_str(), || ())
} else {
println!("\nTrying to log into the created account using given seed from file...");
Authenticator::login_with_seed(seed.as_str(), || ())
});
println!("Success !");
let num_invites = value_t!(matches, "num-invites", usize).unwrap_or_else(|_| {
println!("\n----------- Enter number of invitations to generate ---------------");
let mut num = String::new();
let _ = std::io::stdin().read_line(&mut num);
num = num.trim().to_string();
unwrap!(num.parse::<usize>())
});
println!("\nGenerating {} invites...", num_invites);
for i in 0..num_invites {
let inv = generate_random_printable(INVITE_TOKEN_SIZE);
let id = XorName(sha3_256(inv.as_bytes()));
let perms = btree_map![User::Anyone => PermissionSet::new()
.allow(Action::Insert)
.allow(Action::Update)
.allow(Action::Delete)
.allow(Action::ManagePermissions)];
let data = btree_map![];
let (tx, rx) = mpsc::channel();
unwrap!(auth.send(move |client| {
let owner_key = unwrap!(client.owner_key());
let md = unwrap!(MutableData::new(
id,
INVITE_TOKEN_TYPE_TAG,
perms,
data,
btree_set![owner_key]
));
client
.put_mdata(md)
.then(move |_| {
unwrap!(tx.send(()));
Ok(())
})
.into_box()
.into()
}));
unwrap!(rx.recv());
let mut output2 = unwrap!(output.try_clone());
unwrap!(writeln!(output2, "{}", inv));
println!("Generated invite {} / {}", i + 1, num_invites);
}
println!("----------- Done -----------");
}
fn generate_random_printable(len: usize) -> String {
thread_rng().gen_ascii_chars().take(len).collect()
}