Skip to content

Commit

Permalink
wash par implementation (wasmCloud#4)
Browse files Browse the repository at this point in the history
* Migrated functionality for claims from wascap crate

* Migrated functionality for keys from nkeys crate

* Migrated functionality for lattice from latticeclient crate

* Updated CLI to support keys, claims, and lattice commands

* Added par subcommand, created ability for auto-generating keys during par signing

* pinned dependencies, beautified wash par inspect output, updated par README

* Bumped version

* created result error type for par module

* changed generated message

Co-authored-by: Brooks Townsend <[email protected]>
  • Loading branch information
brooksmtownsend and brooksmtownsend authored Oct 26, 2020
1 parent 85fc686 commit c215ff2
Show file tree
Hide file tree
Showing 6 changed files with 476 additions and 48 deletions.
3 changes: 2 additions & 1 deletion wash/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wash"
version = "0.1.0"
version = "0.1.1"
authors = ["Brooks Townsend <[email protected]>"]
edition = "2018"
repository = "https://github.com/wascc/wash"
Expand All @@ -24,3 +24,4 @@ nkeys = "0.0.11"
latticeclient = "0.4.0"
wascap = "0.5.1"
term-table = "1.3.0"
provider-archive = "0.1.2"
27 changes: 20 additions & 7 deletions wash/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ OPTIONS:
-c, --cap <capabilities>... Add custom capabilities
-x, --expires <expires-in-days> Indicates the token expires in the given amount of days. If this option is left
off, the token will never expire
-i, --issuer <issuer-key-path> Issuer seed key path (usually a .nk file). If this option is left off, `wash` will attempt to locate an account key at `$HOME/.wash/keys/<module>_account.nk`, and if it is not found then an issuer key will be generated and placed in `$HOME/.wash/keys/<module>_account.nk`. You can also override this directory by setting the `WASH_HOME` environment variable.
-i, --issuer <issuer-key-path> Issuer seed key path (usually a .nk file). If this option is left off, `wash` will attempt to locate an account key at `$HOME/.wash/keys/<module>_account.nk`, and if it is not found then an issuer key will be generated and placed in `$HOME/.wash/keys/<module>_account.nk`. You can also override this directory by setting the `WASH_KEYS` environment variable.
-n, --name <name> A human-readable, descriptive name for the token
-b, --nbf <not-before-days> Period in days that must elapse before this token is valid. If this option is
left off, the token will be valid immediately
-r, --rev <rev> Revision number
-u, --subject <subject-key-path> Subject seed key path (usually a .nk file). If this option is left off, `wash` will attempt to locate a module key at `$HOME/.wash/keys/<module>_module.nk`, and if it is not found then a module key will be generated and placed in `$HOME/.wash/keys/<module>_module.nk`. You can also override this directory by setting the `WASH_HOME` environment variable.
-u, --subject <subject-key-path> Subject seed key path (usually a .nk file). If this option is left off, `wash` will attempt to locate a module key at `$HOME/.wash/keys/<module>_module.nk`, and if it is not found then a module key will be generated and placed in `$HOME/.wash/keys/<module>_module.nk`. You can also override this directory by setting the `WASH_KEYS` environment variable.
-t, --tag <tags>... A list of arbitrary tags to be embedded in the token
-v, --ver <ver> Human-readable version string
Expand All @@ -66,7 +66,6 @@ FLAGS:
SUBCOMMANDS:
account Generate a signed JWT for an account
actor Generate a signed JWT for an actor module
help Prints this message or the help of the given subcommand(s)
operator Generate a signed JWT for an operator
```

Expand All @@ -91,7 +90,7 @@ FLAGS:
-h, --help Prints help information
OPTIONS:
-d, --directory <keysdirectory> The directory where keys are stored for listing. Defaults to `$HOME/.wash/keys`, and can also be overwritten by setting the WASH_HOME environment variable.
-d, --directory <keysdirectory> The directory where keys are stored for listing. Defaults to `$HOME/.wash/keys`, and can also be overwritten by setting the WASH_KEYS environment variable.
ARGS:
<keyname> The name of the key to output
Expand All @@ -105,7 +104,7 @@ FLAGS:
-h, --help Prints help information
OPTIONS:
-d, --directory <keysdirectory> The directory where keys are stored for listing. Defaults to `$HOME/.wash/keys`, and can also be overwritten by setting the WASH_HOME environment variable.
-d, --directory <keysdirectory> The directory where keys are stored for listing. Defaults to `$HOME/.wash/keys`, and can also be overwritten by setting the WASH_KEYS environment variable.
```

### lattice
Expand All @@ -128,13 +127,28 @@ OPTIONS:
LATTICE_HOST] [default: 127.0.0.1]
SUBCOMMANDS:
help Prints this message or the help of the given subcommand(s)
list List entities of various types within the lattice
start Hold a lattice auction for a given actor and start it if a suitable host is found
stop Tell a given host to terminate the given actor
watch Watch events on the lattice
```

### par

```
USAGE:
wash par <SUBCOMMAND> [FLAGS]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
create Build a provider archive file
insert Insert a provider into a provider archive file
inspect Inspect a provider archive file
```

### reg

```
Expand All @@ -146,7 +160,6 @@ FLAGS:
-V, --version Prints version information
SUBCOMMANDS:
help Prints this message or the help of the given subcommand(s)
pull Downloads a blob from an OCI compliant registry
push Uploads a blob to an OCI compliant registry
Expand Down
95 changes: 82 additions & 13 deletions wash/src/claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,30 @@

// extern crate serde_derive;

use serde::{Serialize, Deserialize};
use nkeys::KeyPair;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::{read_to_string, File};
use std::io::Read;
use std::io::Write;
use structopt::clap::AppSettings;
use structopt::StructOpt;
use wascap::jwt::{Account, Actor, Claims, Operator, TokenValidation, WascapEntity, };
use wascap::wasm::{days_from_now_to_jwt_time, sign_buffer_with_claims};
use wascap::caps::*;
use serde::de::DeserializeOwned;
use term_table::{
row::Row,
table_cell::{Alignment, TableCell},
Table, TableStyle,
};
use wascap::caps::*;
use wascap::jwt::{
Account, Actor, CapabilityProvider, Claims, Operator, TokenValidation, WascapEntity,
};
use wascap::wasm::{days_from_now_to_jwt_time, sign_buffer_with_claims};

#[derive(Debug, StructOpt, Clone)]
#[structopt(
global_settings(&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]),
name = "wascap",
about = "A command line utility for viewing, manipulating, and verifying capability claims in WebAssembly modules")]
name = "claims")]
pub struct ClaimsCli {
#[structopt(flatten)]
command: ClaimsCliCommand,
Expand Down Expand Up @@ -72,6 +74,9 @@ enum TokenCommand {
/// Generate a signed JWT for an account
#[structopt(name = "account")]
Account(AccountMetadata),
/// Generate a signed JWT for a service (capability provider)
#[structopt(name = "provider")]
Provider(ProviderMetadata),
}

#[derive(Debug, Clone, StructOpt, Serialize, Deserialize)]
Expand Down Expand Up @@ -130,6 +135,45 @@ struct AccountMetadata {
not_before_days: Option<u64>,
}

#[derive(Debug, Clone, StructOpt)]
struct ProviderMetadata {
/// A descriptive name for the provider
#[structopt(short = "n", long = "name")]
name: String,

/// Capability contract ID that this provider supports
#[structopt(short = "c", long = "capid")]
capid: String,

/// A human-readable string identifying the vendor of this provider (e.g. Redis or Cassandra or NATS etc)
#[structopt(short = "v", long = "vendor")]
vendor: String,

/// Monotonically increasing revision number
#[structopt(short = "r", long = "revision")]
revision: Option<i32>,

/// Human-friendly version string
#[structopt(short = "e", long = "version")]
version: Option<String>,

/// Seed path for the issuer
#[structopt(short = "i", long = "issuer")]
issuer: String,

/// Seed path for the subject
#[structopt(short = "s", long = "subject")]
subject: String,

/// Indicates the token expires in the given amount of days. If this option is left off, the token will never expire
#[structopt(short = "x", long = "expires")]
expires_in_days: Option<u64>,

/// Period in days that must elapse before this token is valid. If this option is left off, the token will be valid immediately
#[structopt(short = "b", long = "nbf")]
not_before_days: Option<u64>,
}

#[derive(StructOpt, Debug, Clone, Serialize, Deserialize)]
struct ActorMetadata {
/// Enable the Key/Value Store standard capability
Expand Down Expand Up @@ -194,7 +238,7 @@ pub fn handle_command(cli: ClaimsCli) -> Result<(), Box<dyn ::std::error::Error>
match cli.command {
ClaimsCliCommand::Inspect { file, raw } => render_caps(&file, raw),
ClaimsCliCommand::Sign(signcmd) => sign_file(&signcmd),
ClaimsCliCommand::Token (gencmd) => generate_token(&gencmd),
ClaimsCliCommand::Token(gencmd) => generate_token(&gencmd),
}
}

Expand All @@ -203,6 +247,7 @@ fn generate_token(cmd: &TokenCommand) -> Result<(), Box<dyn ::std::error::Error>
TokenCommand::Actor(actor) => generate_actor(actor),
TokenCommand::Operator(operator) => generate_operator(operator),
TokenCommand::Account(account) => generate_account(account),
TokenCommand::Provider(provider) => generate_provider(provider),
}
}

Expand Down Expand Up @@ -325,6 +370,28 @@ fn generate_account(account: &AccountMetadata) -> Result<(), Box<dyn ::std::erro
Ok(())
}

fn generate_provider(provider: &ProviderMetadata) -> Result<(), Box<dyn ::std::error::Error>> {
let keys = get_keypair_vec(&vec![provider.issuer.clone(), provider.subject.clone()])?;
if keys.len() < 2 {
return Err("must supply two keys - one for the issuer, one for subject".into());
}

let claims: Claims<CapabilityProvider> = Claims::<CapabilityProvider>::with_dates(
provider.name.clone(),
keys[0].public_key(),
keys[1].public_key(),
provider.capid.clone(),
provider.vendor.clone(),
provider.revision.clone(),
provider.version.clone(),
HashMap::new(),
days_from_now_to_jwt_time(provider.not_before_days),
days_from_now_to_jwt_time(provider.expires_in_days),
);
println!("{}", claims.encode(&keys[0])?);
Ok(())
}

fn sign_file(cmd: &SignCommand) -> Result<(), Box<dyn ::std::error::Error>> {
let mut sfile = File::open(&cmd.source).unwrap();
let mut buf = Vec::new();
Expand Down Expand Up @@ -422,9 +489,7 @@ fn render_caps(file: &str, raw: bool) -> Result<(), Box<dyn ::std::error::Error>
}
Ok(())
}
Err(e) => {
Err(Box::new(e))
}
Err(e) => Err(Box::new(e)),
Ok(None) => {
eprintln!("No capabilities discovered in : {}", &file);
Ok(())
Expand All @@ -436,7 +501,7 @@ fn render_caps(file: &str, raw: bool) -> Result<(), Box<dyn ::std::error::Error>
fn render_actor_claims(claims: Claims<Actor>, validation: TokenValidation) -> String {
let mut table = render_core(&claims, validation);

let md = claims.metadata.clone().unwrap();
let md = claims.metadata.clone().unwrap();
let friendly_rev = md.rev.unwrap_or(0);
let friendly_ver = md.ver.unwrap_or_else(|| "None".to_string());
let friendly = format!("{} ({})", friendly_ver, friendly_rev);
Expand All @@ -447,7 +512,11 @@ fn render_actor_claims(claims: Claims<Actor>, validation: TokenValidation) -> St
]));

table.add_row(Row::new(vec![TableCell::new_with_alignment(
if md.provider { "Capability Provider" } else { "Capabilities" },
if md.provider {
"Capability Provider"
} else {
"Capabilities"
},
2,
Alignment::Center,
)]));
Expand Down
Loading

0 comments on commit c215ff2

Please sign in to comment.