Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions src/dfx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ flate2 = "1.0.11"
futures = "0.1.28"
hex = "0.3.2"
ic-http-agent = { path = "../ic_http_agent" }
ic-identity-manager = { path = "../ic_identity_manager" }
indicatif = "0.13.0"
lazy-init = "0.3.0"
lazy_static = "1.4.0"
Expand Down
23 changes: 23 additions & 0 deletions src/dfx/src/config/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,29 @@ impl Cache for DiskBasedCache {
}
}

/// Provides a profile for the user.
pub fn get_profile_path() -> DfxResult<PathBuf> {
let home = std::env::var("HOME")
.map_err(|_| CacheError(CacheErrorKind::CannotFindUserHomeDirectory()))?;

let p = PathBuf::from(home)
.join(".cache")
.join("dfinity")
.join("profile");

if !p.exists() {
if let Err(e) = std::fs::create_dir_all(&p) {
return Err(CacheError(CacheErrorKind::CannotCreateCacheDirectory(p, e)));
}
} else if !p.is_dir() {
return Err(CacheError(CacheErrorKind::CacheShouldBeADirectory(p)));
}

Ok(p)
}

/// Return the binary cache root. It constructs it if not present
/// already.
pub fn get_bin_cache_root() -> DfxResult<PathBuf> {
let home = std::env::var("HOME")
.map_err(|_| CacheError(CacheErrorKind::CannotFindUserHomeDirectory()))?;
Expand Down
17 changes: 13 additions & 4 deletions src/dfx/src/lib/environment.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::config::cache::{Cache, DiskBasedCache};
use crate::config::cache::{get_profile_path, Cache, DiskBasedCache};
use crate::config::dfinity::Config;
use crate::config::dfx_version;
use crate::lib::error::DfxResult;
use crate::lib::identity_interface::Identity;
use crate::lib::progress_bar::ProgressBar;

use ic_http_agent::{Agent, AgentConfig};
use lazy_init::Lazy;
use semver::Version;
use slog::Record;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};
use std::rc::Rc;

Expand Down Expand Up @@ -75,7 +77,7 @@ impl EnvironmentImpl {
.into_path(),
Some(c) => c.get_path().parent().unwrap().join(".dfx"),
};
std::fs::create_dir_all(&temp_dir)?;
create_dir_all(&temp_dir)?;

// Figure out which version of DFX we should be running. This will use the following
// fallback sequence:
Expand Down Expand Up @@ -156,9 +158,14 @@ impl Environment for EnvironmentImpl {
let start = config.get_config().get_defaults().get_start();
let address = start.get_address("localhost");
let port = start.get_port(8000);

// This is the default to keep it simple.
let local_project_identity = match get_profile_path() {
Ok(p) => p,
Err(_) => return None,
};
Agent::new(AgentConfig {
url: format!("http://{}:{}", address, port).as_str(),
signer: Box::new(Identity::new(local_project_identity)),
..AgentConfig::default()
})
.ok()
Expand Down Expand Up @@ -195,13 +202,15 @@ pub struct AgentEnvironment<'a> {

impl<'a> AgentEnvironment<'a> {
pub fn new(backend: &'a dyn Environment, agent_url: &str) -> Self {
let local_project_identity = get_profile_path().expect("Failed to access profile");
AgentEnvironment {
backend,
agent: Agent::new(AgentConfig {
url: agent_url,
signer: Box::new(Identity::new(local_project_identity)),
..AgentConfig::default()
})
.unwrap(),
.expect("Failed to construct agent"),
}
}
}
Expand Down
75 changes: 75 additions & 0 deletions src/dfx/src/lib/identity_interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use ic_http_agent::to_request_id;
use ic_http_agent::AgentError;
use ic_http_agent::Blob;
use ic_http_agent::RequestId;
use ic_http_agent::SignedMessage;
use ic_http_agent::Signer;
use std::path::PathBuf;

pub struct Identity(ic_identity_manager::Identity);

impl Identity {
/// Construct a new identity handling object, providing given
/// configuration.
pub fn new(identity_config_path: PathBuf) -> Self {
Self(
// We panic as discussed, as that should not be the
// case. I personally prefer this to be an error.
ic_identity_manager::Identity::new(identity_config_path)
.expect("Expected a valid identity configuration"),
)
}
}

impl Signer for Identity {
fn sign<'a>(
&self,
request: Box<(dyn erased_serde::Serialize + Send + Sync + 'a)>,
) -> Result<
(
RequestId,
Box<dyn erased_serde::Serialize + Send + Sync + 'a>,
),
AgentError,
> {
let request_id = to_request_id(&request).map_err(AgentError::from)?;
let signature_tuple = self
.0
.sign(Blob::from(request_id).as_slice())
.map_err(|e| AgentError::SigningError(e.to_string()))?;
let signature = Blob::from(signature_tuple.signature.clone());
let sender_pubkey = Blob::from(signature_tuple.public_key);
let signed_request = SignedMessage {
request_with_sender: request,
signature,
sender_pubkey,
};
Ok((request_id, Box::new(signed_request)))
}
}

#[cfg(test)]
mod test {
use super::*;
use proptest::prelude::*;
use serde::Serialize;
use tempfile::tempdir;

// Dummy proptest checking request id is correct for now.
proptest! {
#[test]
fn request_id_identity(request: String) {
let dir = tempdir().unwrap();

#[derive(Clone,Serialize)]
struct TestAPI { inner : String}
let request = TestAPI { inner: request};

let request_with_sender = request.clone();
let actual_request_id = to_request_id(&request_with_sender).expect("Failed to produce request id");

let signer = Identity::new(dir.into_path());
let request_id = signer.sign(Box::new(request)).expect("Failed to sign").0;
assert_eq!(request_id, actual_request_id)
}}
}
1 change: 1 addition & 0 deletions src/dfx/src/lib/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod canister_info;
pub mod environment;
pub mod error;
pub mod identity_interface;
pub mod logger;
pub mod message;
pub mod progress_bar;
Expand Down
2 changes: 2 additions & 0 deletions src/ic_http_agent/src/agent/agent_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub enum AgentError {
ClientError(u16, String),
TimeoutWaitingForResponse,

SigningError(String),

InvalidCborData(serde_cbor::Error),
ReqwestError(reqwest::Error),
SerdeError(SerdeError),
Expand Down
2 changes: 2 additions & 0 deletions src/ic_identity_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ pub mod identity;
pub mod principal;
mod provider;
mod types;

pub use identity::Identity;
2 changes: 1 addition & 1 deletion src/ic_identity_manager/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::types::Signature;
/// constraint, or open connections to all possible means of
/// authentication, that are provided in the identity profile we
/// loaded.
pub trait Provider {
pub trait Provider: Sync {
/// Setup the corresponding principal and return a value
/// that can provide signing.
fn provide(&self) -> Result<Box<dyn IdentityWallet>>;
Expand Down