Skip to content

Commit

Permalink
Feature: Read pem files, like that of dfx (#80)
Browse files Browse the repository at this point in the history
* Feature: Read pem files, like that of dfx

* cargo fmt
  • Loading branch information
matthewhammer authored Aug 9, 2021
1 parent d42d66d commit d86acf8
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 28 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions icmt-sdl2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ ic-agent = "0.5.0"
ic-types = "0.1.3"
candid = "0.6"
ron = "*"
shellexpand = "2.1.0"
pem = "0.8"

#[dependencies.candid]
#git = "https://github.com/dfinity/candid"
Expand Down
58 changes: 35 additions & 23 deletions icmt-sdl2/bin/ic-mt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use sdl2::keyboard::Keycode;
use sdl2::render::{Canvas, RenderTarget};
use sdl2::surface::Surface;
use std::fs;
use std::fs::{File, OpenOptions};
use std::fs::OpenOptions;
use std::io;
use std::io::Write;
use std::path::PathBuf;
Expand Down Expand Up @@ -58,19 +58,24 @@ fn init_log(level_filter: log::LevelFilter) {
const RETRY_PAUSE: Duration = Duration::from_millis(100);
const REQUEST_TIMEOUT: Duration = Duration::from_secs(60);

async fn create_agent(url: &str) -> IcmtResult<Agent> {
//use ring::signature::Ed25519KeyPair;
use ring::rand::SystemRandom;
info!("creating agent.");

// to do -- read identity from a file
let rng = SystemRandom::new();
let pkcs8_bytes = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng)?;
let key_pair = ring::signature::Ed25519KeyPair::from_pkcs8(pkcs8_bytes.as_ref())?;
let ident = ic_agent::identity::BasicIdentity::from_key_pair(key_pair);
async fn create_agent(url: &str, pem_file: &Option<String>) -> IcmtResult<Agent> {
use ring::signature::Ed25519KeyPair;
let keypair = if let Some(pem_path) = pem_file {
let path = resolve_path(&pem_path)?;
let bytes = std::fs::read(&path)?;
info!("Parsing pem file {:?}", path);
let pem = pem::parse(&bytes)?;
info!("Successfully parsed pem file {:?}", path);
pem.contents
} else {
let rng = ring::rand::SystemRandom::new();
Ed25519KeyPair::generate_pkcs8(&rng)?.as_ref().to_vec()
};
let identity =
ic_agent::identity::BasicIdentity::from_key_pair(Ed25519KeyPair::from_pkcs8(&keypair)?);
let agent = Agent::builder()
.with_url(url)
.with_identity(ident)
.with_identity(identity)
.build()?;
info!("built agent.");
if true {
Expand Down Expand Up @@ -154,7 +159,7 @@ async fn do_view_task(
) -> IcmtResult<()> {
/* Create our own agent here since we cannot Send it here from the main thread. */
let canister_id = Principal::from_text(cfg.canister_id.clone()).unwrap();
let agent = create_agent(&cfg.replica_url).await?;
let agent = create_agent(&cfg.replica_url, &cfg.pem_file).await?;
let ctx = ConnectCtx {
cfg: cfg.clone(),
canister_id,
Expand Down Expand Up @@ -184,7 +189,7 @@ async fn do_update_task(
) -> IcmtResult<()> {
/* Create our own agent here since we cannot Send it here from the main thread. */
let canister_id = Principal::from_text(cfg.canister_id.clone()).unwrap();
let agent = create_agent(&cfg.replica_url).await?;
let agent = create_agent(&cfg.replica_url, &cfg.pem_file).await?;
let ctx = ConnectCtx {
cfg,
canister_id,
Expand Down Expand Up @@ -708,7 +713,7 @@ async fn run(cfg: ConnectCfg) -> IcmtResult<()> {
std::fs::create_dir_all(&cfg.cli_opt.capture_output_path)?;
};
let canister_id = Principal::from_text(cfg.canister_id.clone()).unwrap();
let agent = create_agent(&cfg.replica_url).await?;
let agent = create_agent(&cfg.replica_url, &cfg.pem_file).await?;

info!("Connecting to IC canister: {}", canister_id);
let ctx = ConnectCtx {
Expand All @@ -723,6 +728,16 @@ async fn run(cfg: ConnectCfg) -> IcmtResult<()> {
Ok(())
}

pub fn resolve_path(file: &str) -> IcmtResult<PathBuf> {
let file = PathBuf::from(shellexpand::tilde(file).into_owned());
if file.is_absolute() {
Ok(file)
} else {
let base = std::env::current_dir()?;
Ok(base.join(file))
}
}

#[tokio::main]
async fn main() -> IcmtResult<()> {
let cli_opt = CliOpt::from_args();
Expand Down Expand Up @@ -757,23 +772,19 @@ async fn main() -> IcmtResult<()> {
replica_url,
cli_opt,
user_kind,
pem_file: None,
};
run(cfg).await?;
}
CliCommand::Connect {
canister_id,
replica_url,
user_info_text,
pem_file,
} => {
let raw_args: (String, (u8, u8, u8)) = ron::de::from_str(&user_info_text).unwrap();
let user_info: UserInfoCli = {
(
raw_args.0,
(
Nat::from((raw_args.1).0),
Nat::from((raw_args.1).1),
Nat::from((raw_args.1).2),
),
format!("Guest-{}", Local::now().to_rfc3339()),
(Nat::from(255), Nat::from(255), Nat::from(255)),
)
};
let user_kind = UserKind::Local(user_info);
Expand All @@ -782,6 +793,7 @@ async fn main() -> IcmtResult<()> {
replica_url,
cli_opt,
user_kind,
pem_file,
};
run(cfg).await?;
}
Expand Down
8 changes: 4 additions & 4 deletions icmt-sdl2/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ pub enum CliCommand {
Connect {
replica_url: String,
canister_id: String,
/// Initialization arguments, as a Candid textual value (default is empty tuple).
#[structopt(short = "i", long = "user")]
user_info_text: String,
#[structopt(short = "p", long = "pem-file")]
pem_file: Option<String>,
},
#[structopt(
name = "replay",
Expand All @@ -64,7 +63,7 @@ pub enum CliCommand {
canister_id: String,
events_file_path: String,
/// Frame size, in number of events, for the replay's update requests.
#[structopt(short = "s", long = "frame_size", default_value = "6")]
#[structopt(short = "s", long = "frame-size", default_value = "6")]
frame_size: usize,
},
}
Expand All @@ -84,4 +83,5 @@ pub struct ConnectCfg {
pub canister_id: String,
pub replica_url: String,
pub user_kind: crate::types::UserKind,
pub pem_file: Option<String>,
}
10 changes: 9 additions & 1 deletion icmt-sdl2/lib/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use log::error;
pub type IcmtResult<X> = Result<X, IcmtError>;

/// Errors from the mini terminal, or its subcomponents.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum IcmtError {
Candid(std::sync::Arc<candid::Error>),
Agent(), /* Clone => Agent(ic_agent::AgentError) */
Expand All @@ -15,7 +15,15 @@ pub enum IcmtError {
RingKeyRejected(ring::error::KeyRejected),
RingUnspecified(ring::error::Unspecified),
FromHexError(hex::FromHexError),
PemError(pem::PemError),
}

impl std::convert::From<pem::PemError> for IcmtError {
fn from(pe: pem::PemError) -> Self {
IcmtError::PemError(pe)
}
}

impl std::convert::From<hex::FromHexError> for IcmtError {
fn from(fhe: hex::FromHexError) -> Self {
IcmtError::FromHexError(fhe)
Expand Down

0 comments on commit d86acf8

Please sign in to comment.