extern crate chrono; extern crate clap; extern crate orizentic; use chrono::Duration; use clap::{App, Arg, ArgMatches, SubCommand}; use std::env; use orizentic::*; #[derive(Debug)] enum OrizenticErr { ParseError(std::num::ParseIntError), } // ORIZENTIC_DB // ORIZENTIC_SECRET // // list // create // revoke // encode pub fn main() { let db_path = env::var_os("ORIZENTIC_DB").map(|str| { str.into_string() .expect("ORIZENTIC_DB contains invalid Unicode sequences") }); let secret = env::var_os("ORIZENTIC_SECRET").map(|str| { Secret( str.into_string() .map(|s| s.into_bytes()) .expect("ORIZENTIC_SECRET contains invalid Unicode sequences"), ) }); let matches = App::new("orizentic cli") .subcommand(SubCommand::with_name("list")) .subcommand( SubCommand::with_name("create") .arg( Arg::with_name("issuer") .long("issuer") .takes_value(true) .required(true), ) .arg( Arg::with_name("ttl") .long("ttl") .takes_value(true) .required(true), ) .arg( Arg::with_name("resource") .long("resource") .takes_value(true) .required(true), ) .arg( Arg::with_name("username") .long("username") .takes_value(true) .required(true), ) .arg( Arg::with_name("perms") .long("perms") .takes_value(true) .required(true), ), ) .subcommand( SubCommand::with_name("revoke").arg( Arg::with_name("id") .long("id") .takes_value(true) .required(true), ), ) .subcommand( SubCommand::with_name("encode").arg( Arg::with_name("id") .long("id") .takes_value(true) .required(true), ), ) .get_matches(); match matches.subcommand() { ("list", _) => list_tokens(db_path), ("create", Some(args)) => create_token(db_path, secret, args), ("revoke", Some(args)) => revoke_token(db_path, args), ("encode", Some(args)) => encode_token(db_path, secret, args), (cmd, _) => { println!("unknown subcommand: {}", cmd); } } } fn list_tokens(db_path: Option) { let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation"); let claimsets = orizentic::filedb::load_claims_from_file(&db_path_); match claimsets { Ok(claimsets_) => { for claimset in claimsets_ { println!("[{}]", claimset.id); println!("Audience: {}", String::from(claimset.audience)); match claimset.expiration { Some(expiration) => println!( "Expiration: {}", expiration.format("%Y-%m-%d %H:%M:%S") ), None => println!("Expiration: None"), } println!("Issuer: {}", claimset.issuer.0); println!( "Issued At: {}", claimset.issued_at.format("%Y-%m-%d %H:%M:%S") ); println!("Resource Name: {}", claimset.resource.0); let perm_val: String = itertools::Itertools::intersperse( claimset.permissions.0.clone().into_iter(), String::from(", "), ) .collect(); println!("Permissions: {}", perm_val); println!("") } } Err(err) => { println!("claimset failed to load: {}", err); std::process::exit(1); } } } fn create_token(db_path: Option, secret: Option, args: &ArgMatches) { let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation"); let secret_ = secret.expect("ORIZENTIC_SECRET is required for this operation"); let issuer = args .value_of("issuer") .map(|x| Issuer(String::from(x))) .expect("--issuer is a required parameter"); let ttl: Option = args.value_of("ttl").map(|x| { x.parse() .and_then(|d| Ok(TTL(Duration::seconds(d)))) .map_err(|err| OrizenticErr::ParseError(err)) .expect("Failed to parse TTL") }); let resource_name = args .value_of("resource") .map(|x| ResourceName(String::from(x))) .expect("--resource is a required parameter"); let username = args .value_of("username") .map(|x| Username::from(x)) .expect("--username is a required parameter"); let perms: Permissions = args .value_of("perms") .map(|str| Permissions(str.split(',').map(|s| String::from(s)).collect())) .expect("--permissions is a required parameter"); let claimsets = orizentic::filedb::load_claims_from_file(&db_path_); match claimsets { Err(err) => { println!("claimset failed to load: {}", err); std::process::exit(1); } Ok(claimsets_) => { let new_claimset = ClaimSet::new(issuer, ttl, resource_name, username, perms); let mut ctx = orizentic::OrizenticCtx::new(secret_, claimsets_); ctx.add_claimset(new_claimset.clone()); match orizentic::filedb::save_claims_to_file(&ctx.list_claimsets(), &db_path_) { Err(err) => { println!("Failed to write claimset to file: {:?}", err); std::process::exit(1); } Ok(_) => match ctx.encode_claimset(&new_claimset) { Ok(token) => println!("{}", token.text), Err(err) => { println!("token could not be encoded: {:?}", err); std::process::exit(1); } }, } } } } fn revoke_token(db_path: Option, args: &ArgMatches) { let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation"); let claimsets = orizentic::filedb::load_claims_from_file(&db_path_); match claimsets { Err(err) => { println!("claimset failed to load: {}", err); std::process::exit(1); } Ok(claimsets_) => { let id = args .value_of("id") .map(String::from) .expect("--id is a required parameter"); let mut ctx = orizentic::OrizenticCtx::new(Secret(String::from("").into_bytes()), claimsets_); ctx.revoke_by_uuid(&id); match orizentic::filedb::save_claims_to_file(&ctx.list_claimsets(), &db_path_) { Err(err) => { println!("Failed to write claimset to file: {:?}", err); std::process::exit(1); } Ok(_) => {} } } } } fn encode_token(db_path: Option, secret: Option, args: &ArgMatches) { let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation"); let secret_ = secret.expect("ORIZENTIC_SECRET is required for this operation"); let id = args .value_of("id") .map(String::from) .expect("--id is a required parameter"); let claimsets = orizentic::filedb::load_claims_from_file(&db_path_); match claimsets { Err(err) => { println!("claimset failed to load: {}", err); std::process::exit(1); } Ok(claimsets_) => { let ctx = orizentic::OrizenticCtx::new(secret_, claimsets_); let claimset = ctx.find_claimset(&id); match claimset { Some(claimset_) => match ctx.encode_claimset(&claimset_) { Ok(token) => println!("{}", token.text), Err(err) => { println!("token could not be encoded: {:?}", err); std::process::exit(1); } }, None => { println!("No claimset found"); std::process::exit(1); } } } } }