diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd index ffc0097d16..119d5014d3 100644 --- a/Jenkinsfile.cd +++ b/Jenkinsfile.cd @@ -1144,7 +1144,7 @@ def nodejsWrapperPublishing(testEnv, isRelease, library) { testEnv.inside { if (library == 'vcx') { // need addition step for VCX to create .js files - sh "cd $directory && npm run compile" + sh "cd $directory && npm i && npm run compile" } npmPublish(version, suffix, directory) @@ -1429,7 +1429,7 @@ def shell(command) { } def setupRust() { - shell("rustup default 1.31.0") + shell("rustup default 1.32.0") } def androidPublishing() { diff --git a/Jenkinsfile.ci b/Jenkinsfile.ci index 9cc2965793..ca436d7547 100644 --- a/Jenkinsfile.ci +++ b/Jenkinsfile.ci @@ -791,7 +791,7 @@ def shell(command) { } def setupRust() { - shell("rustup default 1.31.0") + shell("rustup default 1.32.0") } def setupBrewPackages() { diff --git a/ci/indy-pool.dockerfile b/ci/indy-pool.dockerfile index eddce0a419..67d51a182b 100644 --- a/ci/indy-pool.dockerfile +++ b/ci/indy-pool.dockerfile @@ -24,9 +24,9 @@ RUN echo "deb https://repo.sovrin.org/deb xenial $indy_stream" >> /etc/apt/sourc RUN useradd -ms /bin/bash -u $uid indy -ARG indy_plenum_ver=1.6.662 +ARG indy_plenum_ver=1.6.705 ARG indy_anoncreds_ver=1.0.32 -ARG indy_node_ver=1.6.772 +ARG indy_node_ver=1.6.839 ARG python3_indy_crypto_ver=0.4.5 ARG indy_crypto_ver=0.4.5 diff --git a/cli/src/commands/ledger.rs b/cli/src/commands/ledger.rs index 5f648fd817..6fa8f25ed0 100644 --- a/cli/src/commands/ledger.rs +++ b/cli/src/commands/ledger.rs @@ -1218,6 +1218,78 @@ pub mod sign_multi_command { } } +pub mod auth_rule_command { + use super::*; + + command!(CommandMetadata::build("auth-rule", "Send AUTH_RULE request to change authentication rules for a ledger transaction.") + .add_required_param("txn_type", "Ledger transaction alias or associated value") + .add_required_param("action", "Type of an action. One of: ADD, EDIT") + .add_required_param("field", "Transaction field") + .add_optional_param("old_value", "Old value of field, which can be changed to a new_value (mandatory for EDIT action)") + .add_required_param("new_value", "New value that can be used to fill the field") + .add_required_param("constraint", r#"Set of constraints required for execution of an action + { + constraint_id - type of a constraint. Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + role - role of a user which satisfy to constrain. + sig_count - the number of signatures required to execution action. + need_to_be_owner - if user must be an owner of transaction. + metadata - additional parameters of the constraint. + } + can be combined by + { + constraint_id: <"AND" or "OR"> + auth_constraints: [, ] + } + "#) + .add_example(r#"ledger auth-rule txn_type=NYM action=ADD field=role new_value=101 constraint={"sig_count":1,"role":0,"constraint_id":"role","need_to_be_owner":false}"#) + .add_example(r#"ledger auth-rule txn_type=NYM action=EDIT field=role old_value=101 new_value=0 constraint={"sig_count":1,"role":0,"constraint_id":"role","need_to_be_owner":false}"#) + .finalize() + ); + + fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> { + trace!("execute >> ctx {:?} params {:?}", ctx, params); + + let (pool_handle, pool_name) = ensure_connected_pool(&ctx)?; + let (wallet_handle, wallet_name) = ensure_opened_wallet(&ctx)?; + let submitter_did = ensure_active_did(&ctx)?; + + let txn_type = get_str_param("txn_type", params).map_err(error_err!())?; + let action = get_str_param("action", params).map_err(error_err!())?; + let field = get_str_param("field", params).map_err(error_err!())?; + let old_value = get_opt_str_param("old_value", params).map_err(error_err!())?; + let new_value = get_str_param("new_value", params).map_err(error_err!())?; + let constraint = get_str_param("constraint", params).map_err(error_err!())?; + + let request = Ledger::build_auth_rule_request(&submitter_did, txn_type, &action.to_uppercase(), field, old_value, new_value, constraint) + .map_err(|err| handle_indy_error(err, None, None, None))?; + + let response_json = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &submitter_did, &request) + .map_err(|err| handle_indy_error(err, Some(&submitter_did), Some(&pool_name), Some(&wallet_name)))?; + + let mut response: Response = serde_json::from_str::>(&response_json) + .map_err(|err| println_err!("Invalid data has been received: {:?}", err))?; + + if let Some(result) = response.result.as_mut() { + result["txn"]["data"]["auth_type"] = get_txn_title(&result["txn"]["data"]["auth_type"]); + result["txn"]["data"]["constraint"] = serde_json::Value::String(::serde_json::to_string_pretty(&result["txn"]["data"]["constraint"]).unwrap()); + } + + let res = handle_transaction_response(response) + .map(|result| print_transaction_response(result, + "Auth Rule request has been sent to Ledger.", + None, + &mut vec![("auth_type", "Txn Type"), + ("auth_action", "Action"), + ("field", "Field"), + ("old_value", "Old Value"), + ("new_value", "New Value"), + ("constraint", "Constraint")]))?; + + trace!("execute << {:?}", res); + Ok(res) + } +} + pub fn set_request_fees(request: &mut String, wallet_handle: i32, submitter_did: Option<&str>, fees_inputs: &Option>, fees_outputs: &Option>, extra: Option<&str>) -> Result, ()> { let mut payment_method: Option = None; if let &Some(ref inputs) = fees_inputs { @@ -1413,6 +1485,33 @@ fn get_role_title(role: &serde_json::Value) -> serde_json::Value { }.to_string()) } +fn get_txn_title(role: &serde_json::Value) -> serde_json::Value { + serde_json::Value::String(match role.as_str() { + Some("0") => "NODE", + Some("1") => "NYM", + Some("3") => "GET_TXN", + Some("100") => "ATTRIB", + Some("101") => "SCHEMA", + Some("104") => "GET_ATTR", + Some("105") => "GET_NYM", + Some("107") => "GET_SCHEMA", + Some("108") => "GET_CRED_DEF", + Some("102") => "CRED_DEF", + Some("109") => "POOL_UPGRADE", + Some("111") => "POOL_CONFIG", + Some("113") => "REVOC_REG_DEF", + Some("114") => "REVOC_REG_ENTRY", + Some("115") => "GET_REVOC_REG_DEF", + Some("116") => "GET_REVOC_REG", + Some("117") => "GET_REVOC_REG_DELTA", + Some("118") => "POOL_RESTART", + Some("119") => "GET_VALIDATOR_INFO", + Some("120") => "AUTH_RULE", + Some(val) => val, + _ => "-" + }.to_string()) +} + fn timestamp_to_datetime(_time: i64) -> String { NaiveDateTime::from_timestamp(_time, 0).to_string() } @@ -1444,7 +1543,7 @@ pub struct ReplyResult { pub mod tests { use super::*; use commands::wallet::tests::{create_and_open_wallet, close_and_delete_wallet, open_wallet, close_wallet}; - use commands::pool::tests::{disconnect_and_delete_pool}; + use commands::pool::tests::disconnect_and_delete_pool; use commands::did::tests::{new_did, use_did, SEED_TRUSTEE, DID_TRUSTEE, DID_MY1, VERKEY_MY1, SEED_MY3, DID_MY3, VERKEY_MY3}; #[cfg(feature = "nullpay_plugin")] use commands::common::tests::{load_null_payment_plugin, NULL_PAYMENT_METHOD}; @@ -3473,6 +3572,35 @@ pub mod tests { } } + mod auth_rule { + use super::*; + + const ROLE_CONSTRAINT: &str = r#"{ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }"#; + + #[test] + pub fn auth_rule_works() { + let ctx = setup_with_wallet_and_pool(); + use_trustee(&ctx); + { + let cmd = auth_rule_command::new(); + let mut params = CommandParams::new(); + params.insert("txn_type", "NYM".to_string()); + params.insert("action", "add".to_string()); + params.insert("field", "role".to_string()); + params.insert("new_value", "101".to_string()); + params.insert("constraint", ROLE_CONSTRAINT.to_string()); + cmd.execute(&ctx, ¶ms).unwrap(); + } + tear_down_with_wallet_and_pool(&ctx); + } + } + fn create_new_did(ctx: &CommandContext) -> (String, String) { let (wallet_handle, _) = get_opened_wallet(ctx).unwrap(); Did::new(wallet_handle, "{}").unwrap() diff --git a/cli/src/libindy/ledger.rs b/cli/src/libindy/ledger.rs index a15dd3aed6..4c1322b217 100644 --- a/cli/src/libindy/ledger.rs +++ b/cli/src/libindy/ledger.rs @@ -77,7 +77,18 @@ impl Ledger { pub fn indy_build_pool_upgrade_request(submitter_did: &str, name: &str, version: &str, action: &str, sha256: &str, timeout: Option, schedule: Option<&str>, justification: Option<&str>, reinstall: bool, force: bool, package: Option<&str>) -> Result { ledger::build_pool_upgrade_request(submitter_did, name, version, action, sha256, - timeout, schedule, justification, - reinstall, force, package).wait() + timeout, schedule, justification, + reinstall, force, package).wait() + } + + pub fn build_auth_rule_request(submitter_did: &str, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: &str, + constraint: &str, ) -> Result { + ledger::build_auth_rule_request(submitter_did, txn_type, action, field, + old_value, new_value, constraint).wait() } } \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 1e58388311..b8f7ab9619 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -126,6 +126,7 @@ fn build_executor() -> CommandExecutor { .add_command(ledger::set_fees_prepare_command::new()) .add_command(ledger::verify_payment_receipt_command::new()) .add_command(ledger::sign_multi_command::new()) + .add_command(ledger::auth_rule_command::new()) .finalize_group() .add_group(payment_address::group::new()) .add_command(payment_address::create_command::new()) diff --git a/docs/design/001-cli/README.md b/docs/design/001-cli/README.md index 1100ed366a..6523f95116 100644 --- a/docs/design/001-cli/README.md +++ b/docs/design/001-cli/README.md @@ -333,6 +333,12 @@ Send custom transaction with user defined json body and optional signature ledger custom [txn=] [sign=] ``` +#### AUTH_RULE transaction +Send AUTH_RULE transaction +``` +ledger auth-rule txn_type= action= field= [old_value=] new_value= constraint=<{constraint json}> +``` + #### GET_PAYMENT_SOURCES transaction Send GET_PAYMENT_SOURCES transaction ``` diff --git a/libindy/ci/amazon.dockerfile b/libindy/ci/amazon.dockerfile index 80329b91de..72c6464574 100755 --- a/libindy/ci/amazon.dockerfile +++ b/libindy/ci/amazon.dockerfile @@ -39,7 +39,7 @@ RUN wget https://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-mav RUN sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo RUN yum install -y apache-maven -ENV RUST_ARCHIVE=rust-1.31.0-x86_64-unknown-linux-gnu.tar.gz +ENV RUST_ARCHIVE=rust-1.32.0-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE RUN mkdir -p /rust @@ -74,6 +74,4 @@ RUN cd /tmp && \ RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN cargo install --git https://github.com/DSRCorporation/cargo-test-xunit - WORKDIR /home/indy diff --git a/libindy/ci/ubuntu.dockerfile b/libindy/ci/ubuntu.dockerfile index 380cd6bf12..a69723353e 100755 --- a/libindy/ci/ubuntu.dockerfile +++ b/libindy/ci/ubuntu.dockerfile @@ -62,7 +62,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN useradd -ms /bin/bash -u $uid indy USER indy -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.31.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.32.0 ENV PATH /home/indy/.cargo/bin:$PATH # Install clippy to the Rust toolchain diff --git a/libindy/include/indy_ledger.h b/libindy/include/indy_ledger.h index d2a511ab06..06ecda893b 100644 --- a/libindy/include/indy_ledger.h +++ b/libindy/include/indy_ledger.h @@ -955,6 +955,52 @@ extern "C" { const char* response_metadata) ); + /// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + /// + /// #Params + /// command_handle: command handle to map callback to caller context. + /// txn_type: ledger transaction alias or associated value. + /// action: type of an action. + /// Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). + /// field: transaction field. + /// old_value: old value of a field, which can be changed to a new_value (mandatory for EDIT action). + /// new_value: new value that can be used to fill the field. + /// constraint: set of constraints required for execution of an action in the following format + /// { + /// constraint_id - type of a constraint. + /// Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + /// role - role of a user which satisfy to constrain. + /// sig_count - the number of signatures required to execution action. + /// need_to_be_owner - if user must be an owner of transaction. + /// metadata - additional parameters of the constraint. + /// } + /// can be combined by + /// { + /// 'constraint_id': <"AND" or "OR"> + /// 'auth_constraints': [, ] + /// } + /// + /// cb: Callback that takes command result as parameter. + /// + /// #Returns + /// Request result as json. + /// + /// #Errors + /// Common* + extern indy_error_t indy_build_auth_rule_request(indy_handle_t command_handle, + const char * submitter_did, + const char * txn_type, + const char * action, + const char * field, + const char * old_value, + const char * new_value, + const char * constraint, + + void (*cb)(indy_handle_t command_handle_, + indy_error_t err, + const char* request_json) + ); + #ifdef __cplusplus } #endif diff --git a/libindy/src/api/ledger.rs b/libindy/src/api/ledger.rs index 48ff888af7..c0d05c7db7 100644 --- a/libindy/src/api/ledger.rs +++ b/libindy/src/api/ledger.rs @@ -1834,3 +1834,88 @@ pub extern fn indy_get_response_metadata(command_handle: CommandHandle, res } + +/// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. +/// +/// #Params +/// command_handle: command handle to map callback to caller context. +/// txn_type: ledger transaction alias or associated value. +/// action: type of an action. +/// Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). +/// field: transaction field. +/// old_value: old value of a field, which can be changed to a new_value (mandatory for EDIT action). +/// new_value: new value that can be used to fill the field. +/// constraint: set of constraints required for execution of an action in the following format: +/// { +/// constraint_id - type of a constraint. +/// Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. +/// role - role of a user which satisfy to constrain. +/// sig_count - the number of signatures required to execution action. +/// need_to_be_owner - if user must be an owner of transaction. +/// metadata - additional parameters of the constraint. +/// } +/// can be combined by +/// { +/// 'constraint_id': <"AND" or "OR"> +/// 'auth_constraints': [, ] +/// } +/// +/// cb: Callback that takes command result as parameter. +/// +/// #Returns +/// Request result as json. +/// +/// #Errors +/// Common* +#[no_mangle] +pub extern fn indy_build_auth_rule_request(command_handle: CommandHandle, + submitter_did: *const c_char, + txn_type: *const c_char, + action: *const c_char, + field: *const c_char, + old_value: *const c_char, + new_value: *const c_char, + constraint: *const c_char, + cb: Option) -> ErrorCode { + trace!("indy_build_auth_rule_request: >>> submitter_did: {:?}, txn_type: {:?}, action: {:?}, field: {:?}, \ + old_value: {:?}, new_value: {:?}, constraint: {:?}", + submitter_did, txn_type, action, field, old_value, new_value, constraint); + + check_useful_c_str!(submitter_did, ErrorCode::CommonInvalidParam2); + check_useful_c_str!(txn_type, ErrorCode::CommonInvalidParam3); + check_useful_c_str!(action, ErrorCode::CommonInvalidParam4); + check_useful_c_str!(field, ErrorCode::CommonInvalidParam5); + check_useful_opt_c_str!(old_value, ErrorCode::CommonInvalidParam6); + check_useful_c_str!(new_value, ErrorCode::CommonInvalidParam7); + check_useful_c_str!(constraint, ErrorCode::CommonInvalidParam8); + check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); + + trace!("indy_build_auth_rule_request: entities >>> submitter_did: {:?}, txn_type: {:?}, action: {:?}, field: {:?}, \ + old_value: {:?}, new_value: {:?}, constraint: {:?}", + submitter_did, txn_type, action, field, old_value, new_value, constraint); + + let result = CommandExecutor::instance() + .send(Command::Ledger(LedgerCommand::BuildAuthRuleRequest( + submitter_did, + txn_type, + action, + field, + old_value, + new_value, + constraint, + Box::new(move |result| { + let (err, request_json) = prepare_result_1!(result, String::new()); + trace!("indy_build_auth_rule_request: request_json: {:?}", request_json); + let request_json = ctypes::string_to_cstring(request_json); + cb(command_handle, err, request_json.as_ptr()) + }) + ))); + + let res = prepare_result!(result); + + trace!("indy_build_auth_rule_request: <<< res: {:?}", res); + + res +} diff --git a/libindy/src/commands/ledger.rs b/libindy/src/commands/ledger.rs index 1a72be8ede..9818afe5f4 100644 --- a/libindy/src/commands/ledger.rs +++ b/libindy/src/commands/ledger.rs @@ -184,6 +184,15 @@ pub enum LedgerCommand { GetResponseMetadata( String, // response Box) + Send>), + BuildAuthRuleRequest( + String, // submitter did + String, // auth type + String, // auth action + String, // field + Option, // old value + String, // new value + String, // constraint + Box) + Send>), } pub struct LedgerCommandExecutor { @@ -361,6 +370,10 @@ impl LedgerCommandExecutor { info!(target: "ledger_command_executor", "GetResponseMetadata command received"); cb(self.get_response_metadata(&response)); } + LedgerCommand::BuildAuthRuleRequest(submitter_did, txn_type, action, field, old_value, new_value, constraint, cb) => { + info!(target: "ledger_command_executor", "BuildAuthRuleRequest command received"); + cb(self.build_auth_rule_request(&submitter_did, &txn_type, &action, &field, old_value.as_ref().map(String::as_str), &new_value, &constraint)); + } }; } @@ -890,6 +903,26 @@ impl LedgerCommandExecutor { Ok(res) } + fn build_auth_rule_request(&self, + submitter_did: &str, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: &str, + constraint: &str) -> IndyResult { + debug!("build_auth_rule_request >>> submitter_did: {:?}, txn_type: {:?}, action: {:?}, field: {:?}, \ + old_value: {:?}, new_value: {:?}, constraint: {:?}", submitter_did, txn_type, action, field, old_value, new_value, constraint); + + self.validate_opt_did(Some(submitter_did))?; + + let res = self.ledger_service.build_auth_rule_request(submitter_did, txn_type, action, field, old_value, new_value, constraint)?; + + debug!("build_auth_rule_request <<< res: {:?}", res); + + Ok(res) + } + fn validate_opt_did(&self, did: Option<&str>) -> IndyResult<()> { match did { Some(did) => Ok(self.crypto_service.validate_did(did)?), diff --git a/libindy/src/domain/ledger/auth_rule.rs b/libindy/src/domain/ledger/auth_rule.rs new file mode 100644 index 0000000000..fbd69733d7 --- /dev/null +++ b/libindy/src/domain/ledger/auth_rule.rs @@ -0,0 +1,64 @@ +use serde_json::Value; + +use super::constants::AUTH_RULE; + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Serialize, PartialEq)] +pub enum AuthAction { + ADD, + EDIT +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(tag = "constraint_id")] +pub enum Constraint { + #[serde(rename = "OR")] + OrConstraint(CombinationConstraint), + #[serde(rename = "AND")] + AndConstraint(CombinationConstraint), + #[serde(rename = "ROLE")] + RoleConstraint(RoleConstraint), +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +pub struct RoleConstraint { + pub sig_count: u32, + pub role: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub need_to_be_owner: Option, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +pub struct CombinationConstraint { + pub auth_constraints: Vec +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct AuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + #[serde(skip_serializing_if = "Option::is_none")] + pub old_value: Option, + pub new_value: String, + pub constraint: Constraint, +} + +impl AuthRuleOperation { + pub fn new(auth_type: String, field: String, auth_action: AuthAction, + old_value: Option, new_value: String, constraint: Constraint) -> AuthRuleOperation { + AuthRuleOperation { + _type: AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + old_value, + new_value, + constraint, + } + } +} \ No newline at end of file diff --git a/libindy/src/domain/ledger/constants.rs b/libindy/src/domain/ledger/constants.rs index 998a8aab89..26f964bbb7 100644 --- a/libindy/src/domain/ledger/constants.rs +++ b/libindy/src/domain/ledger/constants.rs @@ -17,10 +17,47 @@ pub const GET_REVOC_REG_DEF: &str = "115"; pub const GET_REVOC_REG: &str = "116"; pub const GET_REVOC_REG_DELTA: &str = "117"; pub const GET_VALIDATOR_INFO: &str = "119"; +pub const AUTH_RULE: &str = "120"; pub const GET_DDO: &str = "120";//TODO change number +pub const REQUESTS: [&str; 21] = [NODE, NYM, GET_TXN, ATTRIB, SCHEMA, CRED_DEF, GET_ATTR, GET_NYM, GET_SCHEMA, + GET_CRED_DEF, POOL_UPGRADE, POOL_RESTART, POOL_CONFIG, REVOC_REG_DEF, REVOC_REG_ENTRY, GET_REVOC_REG_DEF, + GET_REVOC_REG, GET_REVOC_REG_DELTA, GET_VALIDATOR_INFO, AUTH_RULE, GET_DDO]; + pub const TRUSTEE: &str = "0"; pub const STEWARD: &str = "2"; pub const TRUST_ANCHOR: &str = "101"; pub const NETWORK_MONITOR: &str = "201"; pub const ROLE_REMOVE: &str = ""; + + +pub fn txn_name_to_code(txn: &str) -> Option<&str> { + if REQUESTS.contains(&txn) { + return Some(txn) + } + + match txn { + "NODE" => Some(NODE), + "NYM" => Some(NYM), + "GET_TXN" => Some(GET_TXN), + "ATTRIB" => Some(ATTRIB), + "SCHEMA" => Some(SCHEMA), + "CRED_DEF" | "CLAIM_DEF" => Some(CRED_DEF), + "GET_ATTR" => Some(GET_ATTR), + "GET_NYM" => Some(GET_NYM), + "GET_SCHEMA" => Some(GET_SCHEMA), + "GET_CRED_DEF" => Some(GET_CRED_DEF), + "POOL_UPGRADE" => Some(POOL_UPGRADE), + "POOL_RESTART" => Some(POOL_RESTART), + "POOL_CONFIG" => Some(POOL_CONFIG), + "REVOC_REG_DEF" => Some(REVOC_REG_DEF), + "REVOC_REG_ENTRY" => Some(REVOC_REG_ENTRY), + "GET_REVOC_REG_DEF" => Some(GET_REVOC_REG_DEF), + "GET_REVOC_REG" => Some(GET_REVOC_REG), + "GET_REVOC_REG_DELTA" => Some(GET_REVOC_REG_DELTA), + "GET_VALIDATOR_INFO" => Some(GET_VALIDATOR_INFO), + "AUTH_RULE" => Some(AUTH_RULE), + "GET_DDO" => Some(GET_DDO), + _ => None + } +} \ No newline at end of file diff --git a/libindy/src/domain/ledger/mod.rs b/libindy/src/domain/ledger/mod.rs index 1748ecee0c..efaefab01c 100644 --- a/libindy/src/domain/ledger/mod.rs +++ b/libindy/src/domain/ledger/mod.rs @@ -12,3 +12,4 @@ pub mod rev_reg; pub mod response; pub mod validator_info; pub mod constants; +pub mod auth_rule; diff --git a/libindy/src/services/ledger/mod.rs b/libindy/src/services/ledger/mod.rs index 2c842b0bd0..ec6c9bb624 100644 --- a/libindy/src/services/ledger/mod.rs +++ b/libindy/src/services/ledger/mod.rs @@ -12,7 +12,7 @@ use domain::anoncreds::revocation_registry_definition::{RevocationRegistryDefini use domain::anoncreds::revocation_registry_delta::{RevocationRegistryDelta, RevocationRegistryDeltaV1}; use domain::anoncreds::schema::{Schema, SchemaV1, MAX_ATTRIBUTES_COUNT}; use domain::ledger::attrib::{AttribOperation, GetAttribOperation}; -use domain::ledger::constants::{GET_VALIDATOR_INFO, NYM, POOL_RESTART, ROLE_REMOVE, STEWARD, TRUST_ANCHOR, TRUSTEE, NETWORK_MONITOR}; +use domain::ledger::constants::{GET_VALIDATOR_INFO, NYM, POOL_RESTART, ROLE_REMOVE, STEWARD, TRUST_ANCHOR, TRUSTEE, NETWORK_MONITOR, txn_name_to_code}; use domain::ledger::cred_def::{CredDefOperation, GetCredDefOperation, GetCredDefReplyResult}; use domain::ledger::ddo::GetDdoOperation; use domain::ledger::node::{NodeOperation, NodeOperationData}; @@ -25,6 +25,7 @@ use domain::ledger::rev_reg_def::{GetRevocRegDefReplyResult, GetRevRegDefOperati use domain::ledger::schema::{GetSchemaOperation, GetSchemaOperationData, GetSchemaReplyResult, SchemaOperation, SchemaOperationData}; use domain::ledger::txn::{GetTxnOperation, LedgerType}; use domain::ledger::validator_info::GetValidatorInfoOperation; +use domain::ledger::auth_rule::*; use errors::prelude::*; pub mod merkletree; @@ -78,6 +79,35 @@ impl LedgerService { Ok(request) } + pub fn build_auth_rule_request(&self, submitter_did: &str, txn_type: &str, action: &str, field: &str, + old_value: Option<&str>, new_value: &str, constraint: &str) -> IndyResult { + info!("build_auth_rule_request >>> submitter_did: {:?}, txn_type: {:?}, action: {:?}, field: {:?}, \ + old_value: {:?}, new_value: {:?}, constraint: {:?}", submitter_did, txn_type, action, field, old_value, new_value, constraint); + + let txn_type = txn_name_to_code(&txn_type) + .ok_or(err_msg(IndyErrorKind::InvalidStructure, format!("Unsupported `txn_type`: {}", txn_type)))?; + + let action = serde_json::from_str::(&format!("\"{}\"", action)) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Cannot parse action: {}", err)))?; + + if action == AuthAction::EDIT && old_value.is_none() { + return Err(err_msg(IndyErrorKind::InvalidStructure, "`old_value` must be specified for EDIT auth action")); + } + + let constraint = serde_json::from_str::(constraint) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Can not deserialize Constraint: {}", err)))?; + + let operation = AuthRuleOperation::new(txn_type.to_string(), field.to_string(), action, + old_value.map(String::from), new_value.to_string(), constraint); + + let request = Request::build_request(Some(submitter_did), operation) + .to_indy(IndyErrorKind::InvalidState, "AUTH_RULE request json is invalid")?; + + info!("build_auth_rule_request <<< request: {:?}", request); + + Ok(request) + } + pub fn build_get_nym_request(&self, identifier: Option<&str>, dest: &str) -> IndyResult { info!("build_get_nym_request >>> identifier: {:?}, dest: {:?}", identifier, dest); @@ -924,6 +954,130 @@ mod tests { ledger_service.validate_action(&request).unwrap(); } + mod auth_rule { + use super::*; + + const ADD_AUTH_ACTION: &str = "ADD"; + const EDIT_AUTH_ACTION: &str = "EDIT"; + const FIELD: &str = "role"; + const OLD_VALUE: &str = "0"; + const NEW_VALUE: &str = "101"; + + fn _role_constraint() -> Constraint { + Constraint::RoleConstraint(RoleConstraint { + sig_count: 0, + metadata: None, + role: String::new(), + need_to_be_owner: Some(false), + }) + } + + fn _role_constraint_json() -> String { + serde_json::to_string(&_role_constraint()).unwrap() + } + + #[test] + fn build_auth_rule_request_works_for_role_constraint() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + "constraint": _role_constraint(), + }); + + let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, ADD_AUTH_ACTION, FIELD, + None, NEW_VALUE, + &_role_constraint_json()).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_combination_constraints() { + let ledger_service = LedgerService::new(); + + let constraint = Constraint::AndConstraint( + CombinationConstraint { + auth_constraints: vec![ + _role_constraint(), + Constraint::OrConstraint( + CombinationConstraint { + auth_constraints: vec![ + _role_constraint(), _role_constraint(), ] + } + ) + ] + }); + let constraint_json = serde_json::to_string(&constraint).unwrap(); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + "constraint": constraint, + }); + + let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, ADD_AUTH_ACTION, FIELD, + None, NEW_VALUE, + &constraint_json).unwrap(); + + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_edit_auth_action() { + let ledger_service = LedgerService::new(); + + let expected_result = json!({ + "type": AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "old_value": OLD_VALUE, + "new_value": NEW_VALUE, + "auth_action": AuthAction::EDIT, + "constraint": _role_constraint(), + }); + + let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, EDIT_AUTH_ACTION, FIELD, + Some(OLD_VALUE), NEW_VALUE, + &_role_constraint_json()).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn build_auth_rule_request_works_for_edit_auth_action_missed_old_value() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, EDIT_AUTH_ACTION, FIELD, + None, NEW_VALUE, + &_role_constraint_json()); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_auth_rule_request_works_for_invalid_auth_type() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_auth_rule_request(IDENTIFIER, "WRONG", ADD_AUTH_ACTION, FIELD, + None, NEW_VALUE, + &_role_constraint_json()); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + + #[test] + fn build_auth_rule_request_works_for_invalid_auth_action() { + let ledger_service = LedgerService::new(); + + let res = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, "WRONG", FIELD, None, NEW_VALUE, &_role_constraint_json()); + assert_kind!(IndyErrorKind::InvalidStructure, res); + } + } + fn check_request(request: &str, expected_result: serde_json::Value) { let request: serde_json::Value = serde_json::from_str(request).unwrap(); assert_eq!(request["operation"], expected_result); diff --git a/libindy/src/services/pool/catchup.rs b/libindy/src/services/pool/catchup.rs index ebb8dc75dc..e63e358bec 100644 --- a/libindy/src/services/pool/catchup.rs +++ b/libindy/src/services/pool/catchup.rs @@ -17,6 +17,7 @@ pub enum CatchupProgress { MerkleTree, ), NotNeeded(MerkleTree), + Restart(MerkleTree), InProgress, } @@ -51,34 +52,68 @@ pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Opt node_cnt: usize, f: usize, pool_name: &str) -> IndyResult { - if let Some((most_popular_vote, votes_cnt)) = nodes_votes.iter().map(|(key, val)| (key, val.len())).max_by_key(|entry| entry.1) { - let is_consensus_reached = votes_cnt == node_cnt - f; - if is_consensus_reached { - if most_popular_vote.0.eq("timeout") { - return Err(err_msg(IndyErrorKind::PoolTimeout, "Pool timeout")); - } - - return _try_to_catch_up(most_popular_vote, merkle_tree).or_else(|err| { + let (votes, timeout_votes): (HashMap<&(String, usize, Option>), usize>, HashMap<&(String, usize, Option>), usize>) = + nodes_votes + .iter() + .map(|(key, val)| (key, val.len())) + .partition(|((key, _, _), _)| key != "timeout"); + + let most_popular_not_timeout = + votes + .iter() + .max_by_key(|entry| entry.1); + + let timeout_votes = timeout_votes.iter().last(); + + if let Some((most_popular_not_timeout_vote, votes_cnt)) = most_popular_not_timeout { + if *votes_cnt == f + 1 { + return _try_to_catch_up(most_popular_not_timeout_vote, merkle_tree).or_else(|err| { if merkle_tree_factory::drop_cache(pool_name).is_ok() { let merkle_tree = merkle_tree_factory::create(pool_name)?; - _try_to_catch_up(most_popular_vote, &merkle_tree) + _try_to_catch_up(most_popular_not_timeout_vote, &merkle_tree) } else { Err(err) } }); } else { - let reps_cnt: usize = nodes_votes.values().map(|set| set.len()).sum(); - let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt); - let is_consensus_reachable = positive_votes_cnt < node_cnt - f; - if is_consensus_reachable { - //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client - return Err(err_msg(IndyErrorKind::PoolTimeout, "No consensus possible")); - } + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name); + } + } else if let Some((_, votes_cnt)) = timeout_votes { + if *votes_cnt == node_cnt - f { + return _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout")); + } else { + return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name); } } Ok(CatchupProgress::InProgress) } +fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option>), HashSet>, + node_cnt: usize, + votes_cnt: usize, + f: usize, + pool_name: &str) -> IndyResult { + let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum(); + let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt); + let is_consensus_not_reachable = positive_votes_cnt < node_cnt - f; + if is_consensus_not_reachable { + //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client + _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible")) + } else { + Ok(CatchupProgress::InProgress) + } +} + + +fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult { + if merkle_tree_factory::drop_cache(pool_name).is_ok() { + let merkle_tree = merkle_tree_factory::create(pool_name)?; + return Ok(CatchupProgress::Restart(merkle_tree)); + } else { + return Err(err); + } +} + fn _try_to_catch_up(ledger_status: &(String, usize, Option>), merkle_tree: &MerkleTree) -> IndyResult { let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status; let cur_mt_size = merkle_tree.count(); diff --git a/libindy/src/services/pool/events.rs b/libindy/src/services/pool/events.rs index c34f2ca426..f9d0f0987f 100644 --- a/libindy/src/services/pool/events.rs +++ b/libindy/src/services/pool/events.rs @@ -69,6 +69,9 @@ pub enum PoolEvent { usize, //target_mt_size MerkleTree, ), + CatchupRestart( + MerkleTree, + ), CatchupTargetNotFound(IndyError), #[allow(dead_code)] //FIXME PoolOutdated, diff --git a/libindy/src/services/pool/pool.rs b/libindy/src/services/pool/pool.rs index a3731f9ccd..72837fa550 100644 --- a/libindy/src/services/pool/pool.rs +++ b/libindy/src/services/pool/pool.rs @@ -305,6 +305,17 @@ impl> PoolSM { CommandExecutor::instance().send(Command::Pool(pc)).unwrap(); PoolState::Terminated(state.into()) } + PoolEvent::CatchupRestart(merkle_tree) => { + if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle_tree) { + state.networker.borrow_mut().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); + state.request_handler = R::new(state.networker.clone(), _get_f(nodes.len()), &vec![], &nodes, None, &pool_name, timeout, extended_timeout); + let ls = _ledger_status(&merkle_tree); + state.request_handler.process_event(Some(RequestEvent::LedgerStatus(ls, None, Some(merkle_tree)))); + PoolState::GettingCatchupTarget(state) + } else { + PoolState::Terminated(state.into()) + } + } PoolEvent::CatchupTargetFound(target_mt_root, target_mt_size, merkle_tree) => { if let Ok((nodes, remotes)) = _get_nodes_and_remotes(&merkle_tree) { state.networker.borrow_mut().process_event(Some(NetworkerEvent::NodesStateUpdated(remotes))); @@ -605,19 +616,22 @@ fn _get_request_handler_with_ledger_status_sent LedgerStatus{ let protocol_version = ProtocolVersion::get(); - let ls = LedgerStatus { + LedgerStatus { txnSeqNo: merkle.count(), merkleRoot: merkle.root_hash().as_slice().to_base58(), ledgerId: 0, ppSeqNo: None, viewNo: None, protocolVersion: if protocol_version > 1 { Some(protocol_version) } else { None }, - }; - - request_handler.process_event(Some(RequestEvent::LedgerStatus(ls, None, Some(merkle)))); - Ok(request_handler) + } } fn _get_nodes_and_remotes(merkle: &MerkleTree) -> IndyResult<(HashMap>, Vec)> { diff --git a/libindy/src/services/pool/request_handler.rs b/libindy/src/services/pool/request_handler.rs index f0f057943c..5f9dba974e 100644 --- a/libindy/src/services/pool/request_handler.rs +++ b/libindy/src/services/pool/request_handler.rs @@ -546,12 +546,20 @@ impl RequestSM { pool_name: &str) -> (RequestState, Option) { let (finished, result) = RequestSM::_process_catchup_target(mt_root, sz, cons_proof, &node_alias, &mut state, f, nodes, pool_name); - if finished { - state.networker.borrow_mut().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); - (RequestState::finish(), result) - } else { - state.networker.borrow_mut().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); - (RequestState::CatchupConsensus(state), result) + + match (finished, result) { + (true, result) => { + state.networker.borrow_mut().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::finish(), result) + }, + (false, Some(PoolEvent::CatchupRestart(merkle_tree))) => { + state.networker.borrow_mut().process_event(Some(NetworkerEvent::CleanTimeout(req_id, None))); + (RequestState::CatchupConsensus(state), Some(PoolEvent::CatchupRestart(merkle_tree))) + }, + (false, result) => { + state.networker.borrow_mut().process_event(Some(NetworkerEvent::CleanTimeout(req_id, Some(node_alias)))); + (RequestState::CatchupConsensus(state), result) + } } } @@ -579,6 +587,7 @@ impl RequestSM { &pool_name) { Ok(CatchupProgress::InProgress) => (false, None), Ok(CatchupProgress::NotNeeded(merkle_tree)) => (true, Some(PoolEvent::Synced(merkle_tree))), + Ok(CatchupProgress::Restart(merkle_tree)) => (false, Some(PoolEvent::CatchupRestart(merkle_tree))), Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree)) => (true, Some(PoolEvent::CatchupTargetFound(target_mt_root, target_mt_size, merkle_tree))), Err(err) => (true, Some(PoolEvent::CatchupTargetNotFound(err))), @@ -1501,7 +1510,7 @@ pub mod tests { assert_match!(&RequestState::CatchupConsensus(_), &request_handler.request_wrapper.as_ref().unwrap().state); request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some("n3".to_string()), Some(MerkleTree::default())))); - assert_match!(&RequestState::CatchupConsensus(_), &request_handler.request_wrapper.as_ref().unwrap().state); + assert_match!(&RequestState::Finish(_), &request_handler.request_wrapper.as_ref().unwrap().state); request_handler.process_event(Some(RequestEvent::LedgerStatus(LedgerStatus::default(), Some("n4".to_string()), Some(MerkleTree::default())))); assert_match!(RequestState::Finish(_), request_handler.request_wrapper.unwrap().state); } diff --git a/libindy/tests/ledger.rs b/libindy/tests/ledger.rs index 3152375244..489211f9a3 100644 --- a/libindy/tests/ledger.rs +++ b/libindy/tests/ledger.rs @@ -549,7 +549,7 @@ mod high_cases { #[test] #[cfg(feature = "local_nodes_pool")] fn indy_attrib_requests_works_for_raw_value() { - let (wallet_handle, pool_handle, did,_) = utils::setup_new_identity(); + let (wallet_handle, pool_handle, did, _) = utils::setup_new_identity(); let attrib_request = ledger::build_attrib_request(&did, &did, @@ -571,7 +571,7 @@ mod high_cases { #[test] #[cfg(feature = "local_nodes_pool")] fn indy_attrib_requests_works_for_hash_value() { - let (wallet_handle, pool_handle, did,_) = utils::setup_new_identity(); + let (wallet_handle, pool_handle, did, _) = utils::setup_new_identity(); let mut ctx = Hasher::new(MessageDigest::sha256()).unwrap(); ctx.update(&ATTRIB_RAW_DATA.as_bytes()).unwrap(); @@ -597,7 +597,7 @@ mod high_cases { #[test] #[cfg(feature = "local_nodes_pool")] fn indy_attrib_requests_works_for_encrypted_value() { - let (wallet_handle, pool_handle, did,_) = utils::setup_new_identity(); + let (wallet_handle, pool_handle, did, _) = utils::setup_new_identity(); let key = secretbox::gen_key(); let nonce = secretbox::gen_nonce(); @@ -623,7 +623,7 @@ mod high_cases { #[test] #[cfg(feature = "local_nodes_pool")] fn indy_get_attrib_requests_works_for_default_submitter_did() { - let (wallet_handle, pool_handle, did,_) = utils::setup_new_identity(); + let (wallet_handle, pool_handle, did, _) = utils::setup_new_identity(); let attrib_request = ledger::build_attrib_request(&did, &did, @@ -1668,6 +1668,160 @@ mod high_cases { assert!(response_metadata["lastSeqNo"].as_u64().is_none()); } } + + mod auth_rule { + use super::*; + + const ADD_AUTH_ACTION: &str = "ADD"; + const EDIT_AUTH_ACTION: &str = "EDIT"; + const FIELD: &str = "role"; + const OLD_VALUE: &str = "0"; + const NEW_VALUE: &str = "101"; + const ROLE_CONSTRAINT: &str = r#"{ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }"#; + + #[test] + fn indy_build_auth_rule_request_works_for_add_action() { + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": ADD_AUTH_ACTION, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request(DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + NEW_VALUE, + ROLE_CONSTRAINT).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_request_works_for_edit_action() { + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "field": FIELD, + "old_value": OLD_VALUE, + "new_value": NEW_VALUE, + "auth_action": EDIT_AUTH_ACTION, + "constraint": json!({ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }), + }); + + let request = ledger::build_auth_rule_request(DID_TRUSTEE, + constants::NYM, + &EDIT_AUTH_ACTION, + FIELD, + Some(OLD_VALUE), + NEW_VALUE, + ROLE_CONSTRAINT).unwrap(); + check_request(&request, expected_result); + } + + + #[test] + fn indy_build_auth_rule_request_works_for_complex_constraint() { + let constraint = r#"{ + "constraint_id": "AND", + "auth_constraints": [ + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1, + "need_to_be_owner": false, + "metadata": {} + }, + { + "constraint_id": "OR", + "auth_constraints": [ + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1, + "need_to_be_owner": false, + "metadata": {} + }, + { + "constraint_id": "ROLE", + "role": "0", + "sig_count": 1 + } + ] + } + ] + }"#; + + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": ADD_AUTH_ACTION, + "constraint": serde_json::from_str::(constraint).unwrap(), + }); + + let request = ledger::build_auth_rule_request(DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + NEW_VALUE, + constraint).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_request_works_for_invalid_constraint() { + let res = ledger::build_auth_rule_request(DID_TRUSTEE, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + NEW_VALUE, + r#"{"field":"value"}"#); + assert_code!(ErrorCode::CommonInvalidStructure, res); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_request_works() { + let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); + + let auth_rule_request = ledger::build_auth_rule_request(&trustee_did, + constants::NYM, + &ADD_AUTH_ACTION, + FIELD, + None, + NEW_VALUE, + ROLE_CONSTRAINT).unwrap(); + let response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &trustee_did, &auth_rule_request).unwrap(); + pool::check_response_type(&response, ResponseType::REPLY); + + utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); + } + } } mod medium_cases { @@ -2200,7 +2354,7 @@ mod medium_cases { pool::check_response_type(&cred_def_response, ::utils::types::ResponseType::REPLY); let get_cred_def_request = ledger::build_get_cred_def_request(Some(DID_MY1), &cred_def_id).unwrap(); - let get_cred_def_response = ledger::submit_request(pool_handle, &get_cred_def_request).unwrap(); + let get_cred_def_response = ledger::submit_request_with_retries(pool_handle, &get_cred_def_request, &cred_def_response).unwrap(); let (_, cred_def_json) = ledger::parse_get_cred_def_response(&get_cred_def_response).unwrap(); let _cred_def: CredentialDefinitionV1 = serde_json::from_str(&cred_def_json).unwrap(); diff --git a/libindy/tests/utils/ledger.rs b/libindy/tests/utils/ledger.rs index b0db88179d..b3d1b764f4 100644 --- a/libindy/tests/utils/ledger.rs +++ b/libindy/tests/utils/ledger.rs @@ -187,10 +187,10 @@ pub fn register_transaction_parser_for_sp(txn_type: &str, parse: CustomTransacti let err = unsafe { indy_register_transaction_parser_for_sp(command_handle, - txn_type.as_ptr(), - Some(parse), - Some(free), - cb) + txn_type.as_ptr(), + Some(parse), + Some(free), + cb) }; super::results::result_to_empty(err, receiver) @@ -200,6 +200,16 @@ pub fn get_response_metadata(response: &str) -> Result { ledger::get_response_metadata(response).wait() } +pub fn build_auth_rule_request(submitter_did: &str, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: &str, + constraint: &str, ) -> Result { + ledger::build_auth_rule_request(submitter_did, txn_type, action, field, old_value, new_value, constraint).wait() +} + pub fn post_entities() -> (&'static str, &'static str, &'static str) { lazy_static! { static ref COMMON_ENTITIES_INIT: Once = ONCE_INIT; diff --git a/vcx/ci/libindy.dockerfile b/vcx/ci/libindy.dockerfile index 8ec8fd273f..33d2df18da 100644 --- a/vcx/ci/libindy.dockerfile +++ b/vcx/ci/libindy.dockerfile @@ -41,7 +41,7 @@ RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \ && apt-get install -y nodejs # Install Rust -ARG RUST_VER="1.31.0" +ARG RUST_VER="1.32.0" ENV RUST_ARCHIVE=rust-${RUST_VER}-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE diff --git a/vcx/ci/libvcx.dockerfile b/vcx/ci/libvcx.dockerfile index 0e237d3809..9d913dfc2f 100644 --- a/vcx/ci/libvcx.dockerfile +++ b/vcx/ci/libvcx.dockerfile @@ -4,7 +4,7 @@ ARG uid=1000 RUN useradd -ms /bin/bash -u $uid vcx USER vcx -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.31.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.32.0 ENV PATH /home/vcx/.cargo/bin:$PATH WORKDIR /home/vcx ENV PATH /home/vcx:$PATH diff --git a/vcx/dummy-cloud-agent/src/actors/agent_connection.rs b/vcx/dummy-cloud-agent/src/actors/agent_connection.rs index a48cc962e4..97da837f4b 100644 --- a/vcx/dummy-cloud-agent/src/actors/agent_connection.rs +++ b/vcx/dummy-cloud-agent/src/actors/agent_connection.rs @@ -1614,4 +1614,4 @@ mod tests { }) }); } -} +} \ No newline at end of file diff --git a/vcx/dummy-cloud-agent/src/domain/a2a.rs b/vcx/dummy-cloud-agent/src/domain/a2a.rs index d98a5c052c..ac66f22bdb 100644 --- a/vcx/dummy-cloud-agent/src/domain/a2a.rs +++ b/vcx/dummy-cloud-agent/src/domain/a2a.rs @@ -1291,4 +1291,3 @@ struct UnpackMessage { message: String, sender_verkey: Option } - diff --git a/vcx/dummy-cloud-agent/src/domain/internal_message.rs b/vcx/dummy-cloud-agent/src/domain/internal_message.rs index 3b55e880ba..4bb83fd819 100644 --- a/vcx/dummy-cloud-agent/src/domain/internal_message.rs +++ b/vcx/dummy-cloud-agent/src/domain/internal_message.rs @@ -38,7 +38,4 @@ impl InternalMessage { thread, } } -} - - - +} \ No newline at end of file diff --git a/vcx/dummy-cloud-agent/src/domain/invite.rs b/vcx/dummy-cloud-agent/src/domain/invite.rs index 1d43ccd875..1b70b3968c 100644 --- a/vcx/dummy-cloud-agent/src/domain/invite.rs +++ b/vcx/dummy-cloud-agent/src/domain/invite.rs @@ -52,4 +52,4 @@ pub struct AgentDetail { pub did: String, // Agent Verkey pub verkey: String, -} +} \ No newline at end of file diff --git a/vcx/dummy-cloud-agent/src/utils/tests.rs b/vcx/dummy-cloud-agent/src/utils/tests.rs index 8e0caee951..7f5e384e30 100644 --- a/vcx/dummy-cloud-agent/src/utils/tests.rs +++ b/vcx/dummy-cloud-agent/src/utils/tests.rs @@ -237,9 +237,9 @@ pub fn compose_connect(wallet_handle: i32) -> BoxedFuture, Error> { }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - FORWARD_AGENT_DID_VERKEY, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + FORWARD_AGENT_DID_VERKEY, + &msgs).wait().unwrap(); compose_forward(wallet_handle, FORWARD_AGENT_DID, FORWARD_AGENT_DID_VERKEY, msg) } @@ -260,9 +260,9 @@ pub fn compose_signup(wallet_handle: i32, pairwise_did: &str, pairwise_verkey: & let msgs = [A2AMessage::Version1(A2AMessageV1::SignUp(SignUp {}))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - pairwise_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + pairwise_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle,&pairwise_did, FORWARD_AGENT_DID_VERKEY, msg) } @@ -282,9 +282,9 @@ pub fn compose_create_agent(wallet_handle: i32, pairwise_did: &str, pairwise_ver let msgs = vec![A2AMessage::Version1(A2AMessageV1::CreateAgent(CreateAgent {}))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - pairwise_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + pairwise_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle,pairwise_did, FORWARD_AGENT_DID_VERKEY, msg) } @@ -309,9 +309,9 @@ pub fn compose_create_key(wallet_handle: i32, agent_did: &str, agent_verkey: &st }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - agent_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + agent_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle,agent_did, FORWARD_AGENT_DID_VERKEY, msg) } @@ -355,7 +355,7 @@ pub fn decompose_connection_request_created(wallet_handle: i32, msg: &[u8]) -> B assert_eq!(2, msgs.len()); match (msgs.remove(0), msgs.remove(0)) { (A2AMessage::Version1(A2AMessageV1::MessageCreated(msg_created)), - A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::ConnectionRequestResp(msg_details)))) => + A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::ConnectionRequestResp(msg_details)))) => Ok((sender_verkey, msg_created.uid, msg_details.invite_detail)), _ => Err(err_msg("Invalid message")) } @@ -546,9 +546,9 @@ pub fn compose_get_messages_by_connection(wallet_handle: i32, pairwise_dids: Vec::new(), }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - agent_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + agent_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle,agent_did, FORWARD_AGENT_DID_VERKEY, msg) } pub fn decompose_get_messages_by_connection(wallet_handle: i32, msg: &[u8]) -> BoxedFuture<(String, Vec), Error> { @@ -574,9 +574,9 @@ pub fn compose_update_configs(wallet_handle: i32, agent_did: &str, agent_verkey: }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - agent_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + agent_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle, agent_did, FORWARD_AGENT_DID_VERKEY, msg) } @@ -588,9 +588,9 @@ pub fn compose_get_configs(wallet_handle: i32, agent_did: &str, agent_verkey: &s }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - agent_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + agent_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle, agent_did, FORWARD_AGENT_DID_VERKEY, msg) } @@ -614,9 +614,9 @@ pub fn compose_remove_configs(wallet_handle: i32, agent_did: &str, agent_verkey: }))]; let msg = A2AMessage::prepare_authcrypted(wallet_handle, - EDGE_AGENT_DID_VERKEY, - agent_verkey, - &msgs).wait().unwrap(); + EDGE_AGENT_DID_VERKEY, + agent_verkey, + &msgs).wait().unwrap(); compose_forward(wallet_handle, agent_did, FORWARD_AGENT_DID_VERKEY, msg) } diff --git a/vcx/libvcx/Cargo.lock b/vcx/libvcx/Cargo.lock index 15a369b6d9..63ec62b01c 100644 --- a/vcx/libvcx/Cargo.lock +++ b/vcx/libvcx/Cargo.lock @@ -562,6 +562,7 @@ dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "indy 1.8.1", "indy-sys 1.8.1", diff --git a/vcx/libvcx/Cargo.toml b/vcx/libvcx/Cargo.toml index c1ddfa4d98..ddba4ee673 100644 --- a/vcx/libvcx/Cargo.toml +++ b/vcx/libvcx/Cargo.toml @@ -53,6 +53,7 @@ tokio-threadpool = "0.1.6" futures = "0.1.23" libloading = "0.5.0" uuid = {version = "0.7.1", default-features = false, features = ["v4"]} +failure = "0.1.3" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" diff --git a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh index 80775593a2..e05d7df2e5 100755 --- a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh +++ b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh @@ -44,7 +44,7 @@ fi if [[ $RUSTUP_VERSION =~ ^'rustup ' ]]; then rustup update - rustup default 1.31.0 + rustup default 1.32.0 rustup component add rls-preview rust-analysis rust-src echo "Using rustc version $(rustc --version)" rustup target remove aarch64-linux-android armv7-linux-androideabi arm-linux-androideabi i686-linux-android x86_64-linux-android diff --git a/vcx/libvcx/include/vcx.h b/vcx/libvcx/include/vcx.h index 4b4680b116..889427048f 100644 --- a/vcx/libvcx/include/vcx.h +++ b/vcx/libvcx/include/vcx.h @@ -1605,6 +1605,26 @@ vcx_error_t vcx_get_logger(const void* vcx_get_logger, vcx_u32_t line), void (**flushFn)(const void* context) ); +/// Get details for last occurred error. +/// +/// This function should be called in two places to handle both cases of error occurrence: +/// 1) synchronous - in the same application thread +/// 2) asynchronous - inside of function callback +/// +/// NOTE: Error is stored until the next one occurs in the same execution thread or until asynchronous callback finished. +/// Returning pointer has the same lifetime. +/// +/// #Params +/// * `error_json_p` - Reference that will contain error details (if any error has occurred before) +/// in the format: +/// { +/// "backtrace": Optional - error backtrace. +/// Collecting of backtrace can be enabled by setting environment variable `RUST_BACKTRACE=1` +/// "message": str - human-readable error description +/// } +/// +vcx_error_t vcx_get_current_error(const char ** error_json_p); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vcx/libvcx/src/api/connection.rs b/vcx/libvcx/src/api/connection.rs index f01450ed84..2a51ba000b 100644 --- a/vcx/libvcx/src/api/connection.rs +++ b/vcx/libvcx/src/api/connection.rs @@ -1,14 +1,10 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use utils::threadpool::spawn; use std::ptr; -use error::ToErrorCode; -use error::connection::ConnectionError; use connection::{get_source_id, create_connection, create_connection_with_invite, connect, to_string, get_state, release, is_valid_handle, update_state, from_string, get_invite_details, delete_connection}; +use error::prelude::*; /// Delete a Connection object and release its handle /// @@ -30,20 +26,21 @@ pub extern fn vcx_connection_delete_connection(command_handle: u32, err: u32)>) -> u32 { info!("vcx_delete_connection >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + if !is_valid_handle(connection_handle) { - return ConnectionError::InvalidHandle().to_error_code() + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } trace!("vcx_connection_delete_connection(command_handle: {}, connection_handle: {})", command_handle, connection_handle); spawn(move|| { match delete_connection(connection_handle) { Ok(_) => { - trace!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, 0); + trace!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); }, Err(e) => { trace!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, e); - cb(command_handle, e.to_error_code()); + cb(command_handle, e.into()); }, } @@ -71,20 +68,22 @@ pub extern fn vcx_connection_create(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_create >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + trace!("vcx_connection_create(command_handle: {}, source_id: {})", command_handle, source_id); + spawn(move|| { match create_connection(&source_id) { Ok(handle) => { trace!("vcx_connection_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), handle, source_id); + command_handle, error::SUCCESS.message, handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle); }, Err(x) => { warn!("vcx_connection_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, x.to_string(), 0, source_id); - cb(command_handle, x.to_error_code(), 0); + command_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); }, }; @@ -114,21 +113,21 @@ pub extern fn vcx_connection_create_with_invite(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_create_with_invite >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(invite_details, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(invite_details, VcxErrorKind::InvalidOption); trace!("vcx_connection_create_with_invite(command_handle: {}, source_id: {})", command_handle, source_id); spawn(move|| { match create_connection_with_invite(&source_id, &invite_details) { Ok(handle) => { trace!("vcx_connection_create_with_invite_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), handle, source_id); + command_handle, error::SUCCESS.message, handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle); }, Err(x) => { warn!("vcx_connection_create_with_invite_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, x.to_string(), 0, source_id); - cb(command_handle, x.to_error_code(), 0); + command_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); }, }; @@ -160,15 +159,15 @@ pub extern fn vcx_connection_connect(command_handle:u32, cb: Option) -> u32 { info!("vcx_connection_connect >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !is_valid_handle(connection_handle) { error!("vcx_connection_get_state - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let options = if !connection_options.is_null() { - check_useful_opt_c_str!(connection_options, error::INVALID_OPTION.code_num); + check_useful_opt_c_str!(connection_options, VcxErrorKind::InvalidOption); connection_options.to_owned() } else { @@ -185,21 +184,21 @@ pub extern fn vcx_connection_connect(command_handle:u32, match get_invite_details(connection_handle,true) { Ok(x) => { trace!("vcx_connection_connect_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", - command_handle, connection_handle, error_string(0), x, source_id); + command_handle, connection_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(e) => { warn!("vcx_connection_connect_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", - command_handle, connection_handle, error_string(0), "null", source_id); + command_handle, connection_handle, error::SUCCESS.message, "null", source_id); // TODO: why Success????? cb(command_handle, error::SUCCESS.code_num, ptr::null_mut()); }, } }, Err(x) => { warn!("vcx_connection_connect_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}, source_id: {})", - command_handle, connection_handle, x.to_string(), "null", source_id); - cb(command_handle,x.to_error_code(), ptr::null_mut()); + command_handle, connection_handle, x, "null", source_id); + cb(command_handle,x.into(), ptr::null_mut()); }, }; @@ -226,7 +225,7 @@ pub extern fn vcx_connection_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = get_source_id(connection_handle).unwrap_or_default(); trace!("vcx_connection_serialize(command_handle: {}, connection_handle: {}), source_id: {:?}", @@ -234,21 +233,21 @@ pub extern fn vcx_connection_serialize(command_handle: u32, if !is_valid_handle(connection_handle) { error!("vcx_connection_get_state - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { match to_string(connection_handle) { Ok(json) => { trace!("vcx_connection_serialize_cb(command_handle: {}, connection_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, connection_handle, error_string(0), json, source_id); + command_handle, connection_handle, error::SUCCESS.message, json, source_id); let msg = CStringUtils::string_to_cstring(json); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_connection_serialize_cb(command_handle: {}, connection_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, connection_handle, error_string(x), "null", source_id); - cb(command_handle, x, ptr::null_mut()); + command_handle, connection_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); }, }; @@ -275,8 +274,8 @@ pub extern fn vcx_connection_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(connection_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(connection_data, VcxErrorKind::InvalidOption); trace!("vcx_connection_deserialize(command_handle: {}, connection_data: {})", command_handle, connection_data); @@ -285,13 +284,13 @@ pub extern fn vcx_connection_deserialize(command_handle: u32, Ok(x) => { let source_id = get_source_id(x).unwrap_or_default(); trace!("vcx_connection_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {:?}", - command_handle, error_string(0), x, source_id); + command_handle, error::SUCCESS.message, x, source_id); (error::SUCCESS.code_num, x) }, Err(x) => { warn!("vcx_connection_deserialize_cb(command_handle: {}, rc: {}, handle: {} )", - command_handle, error_string(x.to_error_code()), 0); - (x.to_error_code(), 0) + command_handle, x, 0); + (x.into(), 0) }, }; @@ -321,7 +320,7 @@ pub extern fn vcx_connection_update_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_update_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = get_source_id(connection_handle).unwrap_or_default(); trace!("vcx_connection_update_state(command_handle: {}, connection_handle: {}), source_id: {:?}", @@ -329,21 +328,20 @@ pub extern fn vcx_connection_update_state(command_handle: u32, if !is_valid_handle(connection_handle) { error!("vcx_connection_get_state - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { let rc = match update_state(connection_handle) { Ok(x) => { trace!("vcx_connection_update_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", - command_handle, error_string(0), connection_handle, get_state(connection_handle), source_id); + command_handle, error::SUCCESS.message, connection_handle, get_state(connection_handle), source_id); x }, Err(x) => { warn!("vcx_connection_update_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", - // TODO: Refactor Error - command_handle, error_string(x.to_error_code()), connection_handle, get_state(connection_handle), source_id); - x.to_error_code() + command_handle, x, connection_handle, get_state(connection_handle), source_id); + x.into() }, }; let state = get_state(connection_handle); @@ -371,7 +369,7 @@ pub extern fn vcx_connection_get_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_get_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = get_source_id(connection_handle).unwrap_or_default(); trace!("vcx_connection_get_state(command_handle: {}, connection_handle: {}), source_id: {:?}", @@ -379,12 +377,12 @@ pub extern fn vcx_connection_get_state(command_handle: u32, if !is_valid_handle(connection_handle) { error!("vcx_connection_get_state - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { trace!("vcx_connection_get_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", - command_handle, error_string(0), connection_handle, get_state(connection_handle), source_id); + command_handle, error::SUCCESS.message, connection_handle, get_state(connection_handle), source_id); cb(command_handle, error::SUCCESS.code_num, get_state(connection_handle)); Ok(()) @@ -413,7 +411,7 @@ pub extern fn vcx_connection_invite_details(command_handle: u32, cb: Option) -> u32 { info!("vcx_connection_invite_details >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = get_source_id(connection_handle).unwrap_or_default(); trace!("vcx_connection_invite_details(command_handle: {}, connection_handle: {}, abbreviated: {}), source_id: {:?}", @@ -421,21 +419,21 @@ pub extern fn vcx_connection_invite_details(command_handle: u32, if !is_valid_handle(connection_handle) { error!("vcx_connection_get_state - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { match get_invite_details(connection_handle, abbreviated){ Ok(str) => { trace!("vcx_connection_invite_details_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", - command_handle, connection_handle, error_string(0), str, source_id); + command_handle, connection_handle, error::SUCCESS.message, str, source_id); let msg = CStringUtils::string_to_cstring(str); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_connection_invite_details_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}, source_id: {:?})", - command_handle, connection_handle, error_string(x.to_error_code()), "null", source_id); - cb(command_handle, x.to_error_code(), ptr::null_mut()); + command_handle, connection_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); } }; @@ -473,10 +471,10 @@ pub extern fn vcx_connection_send_message(command_handle: u32, cb: Option) -> u32 { info!("vcx_message_send >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg_type, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg_title, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg_type, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg_title, VcxErrorKind::InvalidOption); trace!("vcx_message_send(command_handle: {}, connection_handle: {}, msg: {}, msg_type: {}, msg_title: {})", command_handle, connection_handle, msg, msg_type, msg_title); @@ -485,16 +483,16 @@ pub extern fn vcx_connection_send_message(command_handle: u32, match ::messages::send_message::send_generic_message(connection_handle, &msg, &msg_type, &msg_title) { Ok(x) => { trace!("vcx_connection_send_message_cb(command_handle: {}, rc: {}, msg_id: {})", - command_handle, error::error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg_id = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg_id.as_ptr()); }, Err(e) => { warn!("vcx_connection_send_message_cb(command_handle: {}, rc: {})", - command_handle, error_string(e)); + command_handle, e); - cb(command_handle, e, ptr::null_mut()); + cb(command_handle, e.into(), ptr::null_mut()); }, }; @@ -532,36 +530,36 @@ pub extern fn vcx_connection_sign_data(command_handle: u32, trace!("vcx_connection_sign_data: >>> connection_handle: {}, data_raw: {:?}, data_len: {}", connection_handle, data_raw, data_len); - check_useful_c_byte_array!(data_raw, data_len, error::INVALID_OPTION.code_num, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_byte_array!(data_raw, data_len, VcxErrorKind::InvalidOption, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_connection_sign_data: entities >>> connection_handle: {}, data_raw: {:?}, data_len: {}", connection_handle, data_raw, data_len); if !is_valid_handle(connection_handle) { error!("vcx_connection_sign - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let vk = match ::connection::get_pw_verkey(connection_handle) { Ok(x) => x, - Err(e) => return e.to_error_code(), + Err(e) => return e.into(), }; spawn (move || { match ::utils::libindy::crypto::sign(&vk, &data_raw) { Ok(x) => { trace!("vcx_connection_sign_data_cb(command_handle: {}, connection_handle: {}, rc: {}, signature: {:?})", - command_handle, connection_handle, error_string(0), x); + command_handle, connection_handle, error::SUCCESS.message, x); let (signature_raw, signature_len) = ::utils::cstring::vec_to_pointer(&x); cb(command_handle, error::SUCCESS.code_num, signature_raw, signature_len); }, Err(e) => { warn!("vcx_messages_sign_data_cb(command_handle: {}, rc: {}, signature: null)", - command_handle, error_string(e)); + command_handle, e); - cb(command_handle, e, ptr::null_mut(), 0); + cb(command_handle, e.into(), ptr::null_mut(), 0); }, }; @@ -604,36 +602,36 @@ pub extern fn vcx_connection_verify_signature(command_handle: u32, trace!("vcx_connection_verify_signature: >>> connection_handle: {}, data_raw: {:?}, data_len: {}, signature_raw: {:?}, signature_len: {}", connection_handle, data_raw, data_len, signature_raw, signature_len); - check_useful_c_byte_array!(data_raw, data_len, error::INVALID_OPTION.code_num, error::INVALID_OPTION.code_num); - check_useful_c_byte_array!(signature_raw, signature_len, error::INVALID_OPTION.code_num, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_byte_array!(data_raw, data_len, VcxErrorKind::InvalidOption, VcxErrorKind::InvalidOption); + check_useful_c_byte_array!(signature_raw, signature_len, VcxErrorKind::InvalidOption, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_connection_verify_signature: entities >>> connection_handle: {}, data_raw: {:?}, data_len: {}, signature_raw: {:?}, signature_len: {}", connection_handle, data_raw, data_len, signature_raw, signature_len); if !is_valid_handle(connection_handle) { error!("vcx_connection_verify_signature - invalid handle"); - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let vk = match ::connection::get_their_pw_verkey(connection_handle) { Ok(x) => x, - Err(e) => return e.to_error_code(), + Err(e) => return e.into(), }; spawn (move || { match ::utils::libindy::crypto::verify(&vk, &data_raw, &signature_raw) { Ok(x) => { trace!("vcx_connection_verify_signature_cb(command_handle: {}, rc: {}, valid: {})", - command_handle, error_string(0), x); + command_handle, error::SUCCESS.message, x); cb(command_handle, error::SUCCESS.code_num, x); }, Err(e) => { warn!("vcx_connection_verify_signature_cb(command_handle: {}, rc: {}, valid: {})", - command_handle, error_string(e), false); + command_handle, e, false); - cb(command_handle, e, false); + cb(command_handle, e.into(), false); }, }; @@ -658,13 +656,13 @@ pub extern fn vcx_connection_release(connection_handle: u32) -> u32 { match release(connection_handle) { Ok(_) => { trace!("vcx_connection_release(connection_handle: {}, rc: {}), source_id: {:?}", - connection_handle, error_string(error::SUCCESS.code_num), source_id); + connection_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num }, Err(e) => { warn!("vcx_connection_release(connection_handle: {}), rc: {}), source_id: {:?}", - connection_handle, error_string(e.to_error_code()), source_id); - e.to_error_code() + connection_handle, e, source_id); + e.into() }, } } diff --git a/vcx/libvcx/src/api/credential.rs b/vcx/libvcx/src/api/credential.rs index 7ec7e0efc0..fe82c8bef3 100644 --- a/vcx/libvcx/src/api/credential.rs +++ b/vcx/libvcx/src/api/credential.rs @@ -1,16 +1,12 @@ -extern crate libc; -extern crate serde_json; - -use self::libc::c_char; +use serde_json; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use connection; use credential; use std::ptr; -use error::credential::CredentialError; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Retrieves Payment Info from a Credential /// @@ -26,12 +22,12 @@ use utils::threadpool::spawn; #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_credential_get_payment_info(command_handle: u32, - credential_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + cb: Option) -> u32 { info!("vcx_credential_get_payment_info >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - spawn(move|| { + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + spawn(move || { match credential::get_payment_information(credential_handle) { Ok(p) => { match p { @@ -40,20 +36,18 @@ pub extern fn vcx_credential_get_payment_info(command_handle: u32, trace!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, info.clone()); let msg = CStringUtils::string_to_cstring(info); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } None => { let msg = CStringUtils::string_to_cstring(format!("{{}}")); trace!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, "{}"); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); } } - }, + } Err(e) => { warn!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", - command_handle, - e.to_error_code(), - "{}".to_string()); - cb(command_handle, e.to_error_code(), ptr::null_mut()); + command_handle, e, "{}"); + cb(command_handle, e.into(), ptr::null_mut()); } }; @@ -62,6 +56,7 @@ pub extern fn vcx_credential_get_payment_info(command_handle: u32, error::SUCCESS.code_num } + /// Create a Credential object that requests and receives a credential for an institution /// /// #Params @@ -77,7 +72,6 @@ pub extern fn vcx_credential_get_payment_info(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_credential_create_with_offer(command_handle: u32, @@ -86,25 +80,25 @@ pub extern fn vcx_credential_create_with_offer(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_create_with_offer >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(offer, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(offer, VcxErrorKind::InvalidOption); trace!("vcx_credential_create_with_offer(command_handle: {}, source_id: {}, offer: {})", - command_handle, source_id, offer); + command_handle, source_id, offer); - spawn(move|| { + spawn(move || { match credential::credential_create_with_offer(&source_id, &offer) { Ok(x) => { trace!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {})", - command_handle, source_id, error_string(0), x); + command_handle, source_id, error::SUCCESS.message, x); cb(command_handle, error::SUCCESS.code_num, x) - }, + } Err(x) => { warn!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {})", - command_handle, source_id, x.to_error_code(), 0); - cb(command_handle, x.to_error_code(), 0); - }, + command_handle, source_id, x, 0); + cb(command_handle, x.into(), 0); + } }; Ok(()) @@ -129,31 +123,31 @@ pub extern fn vcx_credential_create_with_offer(command_handle: u32, #[allow(unused_variables, unused_mut)] pub extern fn vcx_get_credential(command_handle: u32, credential_handle: u32, - cb: Option) -> u32 { + cb: Option) -> u32 { info!("vcx_get_credential >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !credential::is_valid_handle(credential_handle) { - return CredentialError::InvalidHandle().to_error_code(); + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_get_credential(command_handle: {}, credential_handle: {}) source_id: {})", - command_handle, credential_handle, source_id); + command_handle, credential_handle, source_id); - spawn(move|| { + spawn(move || { match credential::get_credential(credential_handle) { Ok(s) => { trace!("vcx_get_credential_cb(commmand_handle: {}, rc: {}, msg: {}) source_id: {}", - command_handle, error::SUCCESS.code_num, s, source_id); + command_handle, error::SUCCESS.code_num, s, source_id); let msg = CStringUtils::string_to_cstring(s); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(e) => { error!("vcx_get_credential_cb(commmand_handle: {}, rc: {}, msg: {}) source_id: {}", - command_handle, e.to_error_code(), "".to_string(), source_id); - cb(command_handle, e.to_error_code(), ptr::null_mut()); - }, + command_handle, e, "".to_string(), source_id); + cb(command_handle, e.into(), ptr::null_mut()); + } }; Ok(()) @@ -177,7 +171,6 @@ pub extern fn vcx_get_credential(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_credential_create_with_msgid(command_handle: u32, @@ -187,14 +180,14 @@ pub extern fn vcx_credential_create_with_msgid(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_create_with_msgid >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg_id, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg_id, VcxErrorKind::InvalidOption); trace!("vcx_credential_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", - command_handle, source_id, connection_handle, msg_id); + command_handle, source_id, connection_handle, msg_id); - spawn(move|| { + spawn(move || { match credential::get_credential_offer_msg(connection_handle, &msg_id) { Ok(offer) => { match credential::credential_create_with_offer(&source_id, &offer) { @@ -205,17 +198,17 @@ pub extern fn vcx_credential_create_with_msgid(command_handle: u32, }; let c_offer = CStringUtils::string_to_cstring(offer_string); trace!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {}) source_id: {}", - command_handle, source_id, error_string(0), handle, source_id); + command_handle, source_id, error::SUCCESS.message, handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle, c_offer.as_ptr()) - }, + } Err(e) => { warn!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {}) source_id: {}", - command_handle, source_id, e.to_error_code(), 0, source_id); - cb(command_handle, e.to_error_code(), 0, ptr::null_mut()); - }, + command_handle, source_id, e, 0, source_id); + cb(command_handle, e.into(), 0, ptr::null_mut()); + } }; - }, - Err(e) => cb(command_handle, e.to_error_code(), 0, ptr::null_mut()), + } + Err(e) => cb(command_handle, e.into(), 0, ptr::null_mut()), }; Ok(()) @@ -237,7 +230,6 @@ pub extern fn vcx_credential_create_with_msgid(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_credential_send_request(command_handle: u32, credential_handle: u32, @@ -246,32 +238,32 @@ pub extern fn vcx_credential_send_request(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_send_request >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !credential::is_valid_handle(credential_handle) { - return error::INVALID_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_credential_send_request(command_handle: {}, credential_handle: {}, connection_handle: {}), source_id: {:?}", - command_handle, credential_handle, connection_handle, source_id); + command_handle, credential_handle, connection_handle, source_id); - spawn(move|| { + spawn(move || { match credential::send_credential_request(credential_handle, connection_handle) { Ok(x) => { trace!("vcx_credential_send_request_cb(command_handle: {}, rc: {}) source_id: {}", - command_handle, x.to_string(), source_id); - cb(command_handle,x); - }, + command_handle, x.to_string(), source_id); + cb(command_handle, x); + } Err(e) => { warn!("vcx_credential_send_request_cb(command_handle: {}, rc: {}) source_id: {}", - command_handle, e.to_string(), source_id); - cb(command_handle,e.to_error_code()); - }, + command_handle, e, source_id); + cb(command_handle, e.into()); + } }; Ok(()) @@ -291,35 +283,34 @@ pub extern fn vcx_credential_send_request(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_credential_get_offers(command_handle: u32, - connection_handle: u32, - cb: Option) -> u32 { + connection_handle: u32, + cb: Option) -> u32 { info!("vcx_credential_get_offers >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } trace!("vcx_credential_get_offers(command_handle: {}, connection_handle: {})", - command_handle, connection_handle); + command_handle, connection_handle); - spawn(move|| { + spawn(move || { match credential::get_credential_offer_messages(connection_handle) { Ok(x) => { trace!("vcx_credential_get_offers_cb(command_handle: {}, rc: {}, msg: {})", - command_handle, x.to_string(), x); + command_handle, x.to_string(), x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(x) => { error!("vcx_credential_get_offers_cb(command_handle: {}, rc: {}, msg: null)", - command_handle, x.to_string()); - cb(command_handle, x.to_error_code(), ptr::null_mut()); - }, + command_handle, x); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -340,43 +331,42 @@ pub extern fn vcx_credential_get_offers(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_credential_update_state(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { info!("vcx_credential_update_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !credential::is_valid_handle(credential_handle) { - return error::INVALID_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_credential_update_state(command_handle: {}, credential_handle: {}), source_id: {:?}", - command_handle, credential_handle, source_id); + command_handle, credential_handle, source_id); - spawn(move|| { + spawn(move || { match credential::update_state(credential_handle) { Ok(_) => (), Err(e) => { error!("vcx_credential_update_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, error_string(e), 0, source_id); - cb(command_handle, e, 0) + command_handle, e, 0, source_id); + cb(command_handle, e.into(), 0) } } let state = match credential::get_state(credential_handle) { Ok(s) => { trace!("vcx_credential_update_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, error_string(0), s, source_id); + command_handle, error::SUCCESS.message, s, source_id); cb(command_handle, error::SUCCESS.code_num, s) - }, + } Err(e) => { error!("vcx_credential_update_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, error_string(e.to_error_code()), 0, source_id); - cb(command_handle, e.to_error_code(), 0) + command_handle, e, 0, source_id); + cb(command_handle, e.into(), 0) } }; @@ -402,27 +392,27 @@ pub extern fn vcx_credential_get_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_get_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !credential::is_valid_handle(handle) { - return error::INVALID_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } let source_id = credential::get_source_id(handle).unwrap_or_default(); trace!("vcx_credential_get_state(command_handle: {}, credential_handle: {}), source_id: {:?}", - command_handle, handle, source_id); + command_handle, handle, source_id); - spawn(move|| { + spawn(move || { match credential::get_state(handle) { Ok(s) => { trace!("vcx_credential_get_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, error_string(0), s, source_id); + command_handle, error::SUCCESS.message, s, source_id); cb(command_handle, error::SUCCESS.code_num, s) - }, + } Err(e) => { error!("vcx_credential_get_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, error_string(e.to_error_code()), 0, source_id); - cb(command_handle, e.to_error_code(), 0) + command_handle, e, 0, source_id); + cb(command_handle, e.into(), 0) } }; @@ -450,29 +440,29 @@ pub extern fn vcx_credential_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !credential::is_valid_handle(handle) { - return error::INVALID_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredentialHandle).into() } let source_id = credential::get_source_id(handle).unwrap_or_default(); trace!("vcx_credential_serialize(command_handle: {}, credential_handle: {}), source_id: {:?}", - command_handle, handle, source_id); + command_handle, handle, source_id); - spawn(move|| { + spawn(move || { match credential::to_string(handle) { Ok(x) => { trace!("vcx_credential_serialize_cb(command_handle: {}, rc: {}, data: {}), source_id: {:?}", - command_handle, error_string(0), x, source_id); + command_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(x) => { error!("vcx_credential_serialize_cb(command_handle: {}, rc: {}, data: {}), source_id: {:?}", - command_handle, error_string(x), 0, source_id); - cb(command_handle,x,ptr::null_mut()); - }, + command_handle, x, 0, source_id); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -499,25 +489,25 @@ pub extern fn vcx_credential_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(credential_data, VcxErrorKind::InvalidOption); trace!("vcx_credential_deserialize(command_handle: {}, credential_data: {})", - command_handle, credential_data); + command_handle, credential_data); - spawn(move|| { + spawn(move || { match credential::from_string(&credential_data) { Ok(x) => { trace!("vcx_credential_deserialize_cb(command_handle: {}, rc: {}, credential_handle: {}) source_id: {}", - command_handle, error_string(0), x, credential::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, credential::get_source_id(x).unwrap_or_default()); - cb(command_handle, 0, x); - }, + cb(command_handle, error::SUCCESS.code_num, x); + } Err(x) => { error!("vcx_credential_deserialize_cb(command_handle: {}, rc: {}, credential_handle: {}) source_id: {}", - command_handle, error_string(x), 0, ""); - cb(command_handle, x, 0); - }, + command_handle, x, 0, ""); + cb(command_handle, x.into(), 0); + } }; Ok(()) @@ -541,14 +531,14 @@ pub extern fn vcx_credential_release(handle: u32) -> u32 { match credential::release(handle) { Ok(_) => { trace!("vcx_credential_release(handle: {}, rc: {}), source_id: {:?}", - handle, error_string(0), source_id); + handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num - }, + } Err(e) => { error!("vcx_credential_release(handle: {}, rc: {}), source_id: {:?}", - handle, error_string(e.to_error_code()), source_id); - e.to_error_code() + handle, e, source_id); + e.into() } } } @@ -577,34 +567,35 @@ pub extern fn vcx_credential_get_payment_txn(command_handle: u32, cb: Option) -> u32 { info!("vcx_credential_get_payment_txn >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = credential::get_source_id(handle).unwrap_or_default(); trace!("vcx_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); - spawn(move|| { + spawn(move || { match credential::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { trace!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", - command_handle, error_string(0), x, credential::get_source_id(handle).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, credential::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, 0, msg.as_ptr()); } - Err(_) => { - error!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {}", - command_handle, error_string(error::INVALID_JSON.code_num), "null", credential::get_source_id(handle).unwrap_or_default()); - cb(command_handle, error::INVALID_JSON.code_num, ptr::null_mut()); + Err(e) => { + let err = VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payment txn: {:?}", e)); + error!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {}", + command_handle, err, "null", credential::get_source_id(handle).unwrap_or_default()); + cb(command_handle, err.into(), ptr::null_mut()); } } - }, + } Err(x) => { error!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {}", - command_handle, x.to_string(), "null", credential::get_source_id(handle).unwrap_or_default()); - cb(command_handle, x.to_error_code(), ptr::null()); - }, + command_handle, x, "null", credential::get_source_id(handle).unwrap_or_default()); + cb(command_handle, x.into(), ptr::null()); + } }; Ok(()) @@ -616,6 +607,7 @@ pub extern fn vcx_credential_get_payment_txn(command_handle: u32, #[cfg(test)] mod tests { extern crate serde_json; + use super::*; use std::ffi::CString; use std::time::Duration; @@ -632,9 +624,9 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_credential_create_with_offer(cb.command_handle, - CString::new("test_create").unwrap().into_raw(), - CString::new(::utils::constants::CREDENTIAL_OFFER_JSON).unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new("test_create").unwrap().into_raw(), + CString::new(::utils::constants::CREDENTIAL_OFFER_JSON).unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); assert!(cb.receive(Some(Duration::from_secs(10))).unwrap() > 0); } @@ -653,10 +645,10 @@ mod tests { fn test_vcx_credential_serialize_and_deserialize() { init!("true"); let cb = return_types_u32::Return_U32_STR::new().unwrap(); - let handle = credential::credential_create_with_offer("test_vcx_credential_serialize",::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); + let handle = credential::credential_create_with_offer("test_vcx_credential_serialize", ::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); assert_eq!(vcx_credential_serialize(cb.command_handle, - handle, - Some(cb.get_callback())), error::SUCCESS.code_num); + handle, + Some(cb.get_callback())), error::SUCCESS.code_num); let s = cb.receive(Some(Duration::from_secs(2))).unwrap().unwrap(); let j: Value = serde_json::from_str(&s).unwrap(); assert_eq!(j["version"], DEFAULT_SERIALIZE_VERSION); @@ -671,17 +663,17 @@ mod tests { #[test] fn test_vcx_credential_send_request() { init!("true"); - let handle = credential::credential_create_with_offer("test_send_request",::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); - assert_eq!(credential::get_state(handle).unwrap(),VcxStateType::VcxStateRequestReceived as u32); + let handle = credential::credential_create_with_offer("test_send_request", ::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); + assert_eq!(credential::get_state(handle).unwrap(), VcxStateType::VcxStateRequestReceived as u32); let connection_handle = connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32::new().unwrap(); - assert_eq!(vcx_credential_send_request(cb.command_handle,handle,connection_handle,0, Some(cb.get_callback())), error::SUCCESS.code_num); + assert_eq!(vcx_credential_send_request(cb.command_handle, handle, connection_handle, 0, Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); } #[test] - fn test_vcx_credential_get_new_offers(){ + fn test_vcx_credential_get_new_offers() { init!("true"); let cxn = ::connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); @@ -698,10 +690,10 @@ mod tests { let cxn = ::connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32_U32_STR::new().unwrap(); assert_eq!(vcx_credential_create_with_msgid(cb.command_handle, - CString::new("test_vcx_credential_create").unwrap().into_raw(), - cxn, - CString::new("123").unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new("test_vcx_credential_create").unwrap().into_raw(), + cxn, + CString::new("123").unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); } @@ -711,7 +703,7 @@ mod tests { let handle = credential::from_string(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); assert!(handle > 0); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - let rc = vcx_credential_get_state(cb.command_handle,handle,Some(cb.get_callback())); + let rc = vcx_credential_get_state(cb.command_handle, handle, Some(cb.get_callback())); assert_eq!(rc, error::SUCCESS.code_num); assert_eq!(cb.receive(Some(Duration::from_secs(10))).unwrap(), VcxStateType::VcxStateRequestReceived as u32); } @@ -720,20 +712,19 @@ mod tests { fn test_vcx_credential_update_state() { init!("true"); let cxn = ::connection::tests::build_test_connection(); - ::connection::connect(cxn,None).unwrap(); + ::connection::connect(cxn, None).unwrap(); let handle = credential::from_string(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_CREDENTIAL_OFFER_RESPONSE.to_vec()); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_credential_update_state(cb.command_handle, handle, Some(cb.get_callback())), error::SUCCESS.code_num); - assert_eq!(cb.receive(Some(Duration::from_secs(10))).unwrap(),VcxStateType::VcxStateRequestReceived as u32); + assert_eq!(cb.receive(Some(Duration::from_secs(10))).unwrap(), VcxStateType::VcxStateRequestReceived as u32); let cb = return_types_u32::Return_U32::new().unwrap(); - assert_eq!(vcx_credential_send_request(cb.command_handle, handle, cxn,0, Some(cb.get_callback())), error::SUCCESS.code_num); + assert_eq!(vcx_credential_send_request(cb.command_handle, handle, cxn, 0, Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); - } #[test] - fn test_get_credential(){ + fn test_get_credential() { use utils::constants::FULL_CREDENTIAL_SERIALIZED; init!("true"); let handle = credential::from_string(FULL_CREDENTIAL_SERIALIZED).unwrap(); @@ -744,7 +735,7 @@ mod tests { cb.receive(Some(Duration::from_secs(10))).unwrap().unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); - assert_eq!(vcx_get_credential(cb.command_handle, bad_handle, Some(cb.get_callback())), CredentialError::InvalidHandle().to_error_code()); + assert_eq!(vcx_get_credential(cb.command_handle, bad_handle, Some(cb.get_callback())), error::INVALID_CREDENTIAL_HANDLE.code_num); let handle = credential::from_string(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); @@ -762,7 +753,7 @@ mod tests { vcx_credential_get_payment_txn(cb.command_handle, handle, Some(cb.get_callback())); cb.receive(Some(Duration::from_secs(10))).unwrap(); } - + #[test] fn test_vcx_credential_release() { init!("true"); diff --git a/vcx/libvcx/src/api/credential_def.rs b/vcx/libvcx/src/api/credential_def.rs index 6f3b9eca8e..1b30dc6024 100644 --- a/vcx/libvcx/src/api/credential_def.rs +++ b/vcx/libvcx/src/api/credential_def.rs @@ -1,15 +1,12 @@ -extern crate libc; -extern crate serde_json; - -use self::libc::c_char; +use serde_json; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use std::ptr; use credential_def; use settings; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Create a new CredentialDef object that can create credential definitions on the ledger /// @@ -50,20 +47,20 @@ pub extern fn vcx_credentialdef_create(command_handle: u32, cb: Option) -> u32 { info!("vcx_credentialdef_create >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(credentialdef_name, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(schema_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(tag, error::INVALID_OPTION.code_num); - check_useful_c_str!(revocation_details, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(credentialdef_name, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(schema_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(tag, VcxErrorKind::InvalidOption); + check_useful_c_str!(revocation_details, VcxErrorKind::InvalidOption); let issuer_did: String = if !issuer_did.is_null() { - check_useful_c_str!(issuer_did, error::INVALID_OPTION.code_num); + check_useful_c_str!(issuer_did, VcxErrorKind::InvalidOption); issuer_did.to_owned() } else { match settings::get_config_value(settings::CONFIG_INSTITUTION_DID) { Ok(x) => x, - Err(x) => return x, + Err(x) => return x.into(), } }; @@ -85,13 +82,13 @@ pub extern fn vcx_credentialdef_create(command_handle: u32, revocation_details) { Ok(x) => { trace!("vcx_credential_def_create_cb(command_handle: {}, rc: {}, credentialdef_handle: {}), source_id: {:?}", - command_handle, error_string(0), x, credential_def::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, credential_def::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, Err(x) => { warn!("vcx_credential_def_create_cb(command_handle: {}, rc: {}, credentialdef_handle: {}), source_id: {:?}", - command_handle, error_string(x.to_error_code()), 0, ""); - (x.to_error_code(), 0) + command_handle, x, 0, ""); + (x.into(), 0) }, }; cb(command_handle, rc, handle); @@ -119,28 +116,28 @@ pub extern fn vcx_credentialdef_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_credentialdef_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = credential_def::get_source_id(credentialdef_handle).unwrap_or_default(); trace!("vcx_credentialdef_serialize(command_handle: {}, credentialdef_handle: {}), source_id: {:?}", command_handle, credentialdef_handle, source_id); if !credential_def::is_valid_handle(credentialdef_handle) { - return error::INVALID_CREDENTIAL_DEF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredDefHandle).into() }; spawn(move|| { match credential_def::to_string(credentialdef_handle) { Ok(x) => { trace!("vcx_credentialdef_serialize_cb(command_handle: {}, credentialdef_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, credentialdef_handle, error_string(0), x, source_id); + command_handle, credentialdef_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_credentialdef_serialize_cb(command_handle: {}, credentialdef_handle: {}, rc: {}, state: {}), source_id: {:?}", - command_handle, credentialdef_handle, error_string(x), "null", source_id); - cb(command_handle, x, ptr::null_mut()); + command_handle, credentialdef_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); }, }; @@ -167,8 +164,8 @@ pub extern fn vcx_credentialdef_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_credentialdef_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(credentialdef_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(credentialdef_data, VcxErrorKind::InvalidOption); trace!("vcx_credentialdef_deserialize(command_handle: {}, credentialdef_data: {})", command_handle, credentialdef_data); @@ -176,14 +173,13 @@ pub extern fn vcx_credentialdef_deserialize(command_handle: u32, let (rc, handle) = match credential_def::from_string(&credentialdef_data) { Ok(x) => { trace!("vcx_credentialdef_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", - command_handle, error_string(0), x, credential_def::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, credential_def::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, Err(e) => { - let error_code = e.to_error_code(); warn!("vcx_credentialdef_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", - command_handle, error_code, 0, ""); - (error_code, 0) + command_handle, e, 0, ""); + (e.into(), 0) }, }; cb(command_handle, rc, handle); @@ -209,26 +205,26 @@ pub extern fn vcx_credentialdef_get_cred_def_id(command_handle: u32, cb: Option) -> u32 { info!("vcx_credentialdef_get_cred_def_id >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = credential_def::get_source_id(cred_def_handle).unwrap_or_default(); trace!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}) source_id: {}", command_handle, cred_def_handle, source_id); if !credential_def::is_valid_handle(cred_def_handle) { - return error::INVALID_CREDENTIAL_DEF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredDefHandle).into() } spawn(move|| { match credential_def::get_cred_def_id(cred_def_handle) { Ok(x) => { trace!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}, rc: {}, cred_def_id: {}) source_id: {}", - command_handle, cred_def_handle, error_string(0), x, source_id); + command_handle, cred_def_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}, rc: {}, cred_def_id: {}) source_id: {}", - command_handle, cred_def_handle, x.to_string(), "", source_id); - cb(command_handle, x.to_error_code(), ptr::null_mut()); + command_handle, cred_def_handle, x, "", source_id); + cb(command_handle, x.into(), ptr::null_mut()); }, }; @@ -262,7 +258,7 @@ pub extern fn vcx_credentialdef_get_payment_txn(command_handle: u32, cb: Option) -> u32 { info!("vcx_credentialdef_get_payment_txn >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = credential_def::get_source_id(handle).unwrap_or_default(); trace!("vcx_credentialdef_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); @@ -273,22 +269,23 @@ pub extern fn vcx_credentialdef_get_payment_txn(command_handle: u32, match serde_json::to_string(&x) { Ok(x) => { trace!("vcx_credentialdef_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", - command_handle, error_string(0), x, credential_def::get_source_id(handle).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, credential_def::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, 0, msg.as_ptr()); } - Err(_) => { + Err(e) => { + let err = VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payment txn: {:?}", e)); error!("vcx_credentialdef_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {}", - command_handle, error_string(error::INVALID_JSON.code_num), "null", credential_def::get_source_id(handle).unwrap_or_default()); - cb(command_handle, error::INVALID_JSON.code_num, ptr::null_mut()); + command_handle, err, "null", credential_def::get_source_id(handle).unwrap_or_default()); + cb(command_handle, err.into(), ptr::null_mut()); } } }, Err(x) => { error!("vcx_credentialdef_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {}", - command_handle, x.to_string(), "null", credential_def::get_source_id(handle).unwrap_or_default()); - cb(command_handle, x.to_error_code(), ptr::null()); + command_handle, x, "null", credential_def::get_source_id(handle).unwrap_or_default()); + cb(command_handle, x.into(), ptr::null()); }, }; @@ -313,14 +310,14 @@ pub extern fn vcx_credentialdef_release(credentialdef_handle: u32) -> u32 { match credential_def::release(credentialdef_handle) { Ok(_) => { trace!("vcx_credentialdef_release(credentialdef_handle: {}, rc: {}), source_id: {}", - credentialdef_handle, error_string(0), source_id); + credentialdef_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num }, Err(x) => { warn!("vcx_credentialdef_release(credentialdef_handle: {}, rc: {}), source_id: {}", - credentialdef_handle, x.to_string(), source_id); - x.to_error_code() + credentialdef_handle, x, source_id); + x.into() } } } diff --git a/vcx/libvcx/src/api/disclosed_proof.rs b/vcx/libvcx/src/api/disclosed_proof.rs index 753e0352fe..0e862da96b 100644 --- a/vcx/libvcx/src/api/disclosed_proof.rs +++ b/vcx/libvcx/src/api/disclosed_proof.rs @@ -1,14 +1,11 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use connection; use disclosed_proof; use std::ptr; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Create a proof for fulfilling a corresponding proof request /// @@ -23,7 +20,6 @@ use utils::threadpool::spawn; /// /// #Returns /// Error code as u32 - #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_disclosed_proof_create_with_request(command_handle: u32, @@ -32,25 +28,25 @@ pub extern fn vcx_disclosed_proof_create_with_request(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_create_with_request >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(proof_req, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(proof_req, VcxErrorKind::InvalidOption); trace!("vcx_disclosed_proof_create_with_request(command_handle: {}, source_id: {}, proof_req: {})", - command_handle, source_id, proof_req); + command_handle, source_id, proof_req); - spawn(move|| { - match disclosed_proof::create_proof(&source_id, &proof_req){ + spawn(move || { + match disclosed_proof::create_proof(&source_id, &proof_req) { Ok(x) => { trace!("vcx_disclosed_proof_create_with_request_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), x, source_id); + command_handle,error::SUCCESS.message, x, source_id); cb(command_handle, 0, x); - }, + } Err(x) => { error!("vcx_disclosed_proof_create_with_request_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, source_id); - cb(command_handle, x.to_error_code(), 0); - }, + command_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); + } }; Ok(()) @@ -75,7 +71,6 @@ pub extern fn vcx_disclosed_proof_create_with_request(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_disclosed_proof_create_with_msgid(command_handle: u32, @@ -85,32 +80,32 @@ pub extern fn vcx_disclosed_proof_create_with_msgid(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_create_with_msgid >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg_id, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg_id, VcxErrorKind::InvalidOption); trace!("vcx_disclosed_proof_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", - command_handle, source_id, connection_handle, msg_id); + command_handle, source_id, connection_handle, msg_id); - spawn(move|| { + spawn(move || { match disclosed_proof::get_proof_request(connection_handle, &msg_id) { Ok(request) => { match disclosed_proof::create_proof(&source_id, &request) { Ok(handle) => { trace!("vcx_disclosed_proof_create_with_msgid_cb(command_handle: {}, rc: {}, handle: {}, proof_req: {}) source_id: {}", - command_handle, error_string(0), handle, request, source_id); + command_handle, error::SUCCESS.message, handle, request, source_id); let msg = CStringUtils::string_to_cstring(request); cb(command_handle, error::SUCCESS.code_num, handle, msg.as_ptr()) - }, + } Err(e) => { warn!("vcx_disclosed_proof_create_with_msgid_cb(command_handle: {}, rc: {}, handle: {}, proof_req: {}) source_id: {}", - command_handle, e.to_string(), 0, request, source_id); + command_handle, e, 0, request, source_id); let msg = CStringUtils::string_to_cstring(request); - cb(command_handle, e.to_error_code(), 0, msg.as_ptr()); - }, + cb(command_handle, e.into(), 0, msg.as_ptr()); + } }; - }, - Err(e) => cb(command_handle, e.to_error_code(), 0, ptr::null()), + } + Err(e) => cb(command_handle, e.into(), 0, ptr::null()), }; Ok(()) @@ -132,7 +127,6 @@ pub extern fn vcx_disclosed_proof_create_with_msgid(command_handle: u32, /// /// #Returns /// Error code as u32 - #[no_mangle] pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, proof_handle: u32, @@ -140,32 +134,32 @@ pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_send_proof >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_send_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", - command_handle, proof_handle, connection_handle, source_id); + command_handle, proof_handle, connection_handle, source_id); - spawn(move|| { + spawn(move || { let err = match disclosed_proof::send_proof(proof_handle, connection_handle) { Ok(x) => { trace!("vcx_disclosed_proof_send_proof_cb(command_handle: {}, rc: {}) source_id: {}", - command_handle, error_string(0), source_id); - cb(command_handle,error::SUCCESS.code_num); - }, + command_handle, error::SUCCESS.message, source_id); + cb(command_handle, error::SUCCESS.code_num); + } Err(x) => { error!("vcx_disclosed_proof_send_proof_cb(command_handle: {}, rc: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), source_id); - cb(command_handle,x.to_error_code()); - }, + command_handle, x, source_id); + cb(command_handle, x.into()); + } }; Ok(()) @@ -185,35 +179,34 @@ pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_disclosed_proof_get_requests(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_get_requests >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } trace!("vcx_disclosed_proof_get_requests(command_handle: {}, connection_handle: {})", - command_handle, connection_handle); + command_handle, connection_handle); - spawn(move|| { + spawn(move || { match disclosed_proof::get_proof_request_messages(connection_handle, None) { Ok(x) => { trace!("vcx_disclosed_proof_get_requests_cb(command_handle: {}, rc: {}, msg: {})", - command_handle, error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(x) => { error!("vcx_disclosed_proof_get_requests_cb(command_handle: {}, rc: {}, msg: {})", - command_handle, error_string(0), x); - cb(command_handle, x.to_error_code(), ptr::null_mut()); - }, + command_handle, error::SUCCESS.message, x); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -239,27 +232,27 @@ pub extern fn vcx_disclosed_proof_get_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_get_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {:?}", - command_handle, proof_handle, source_id); + command_handle, proof_handle, source_id); - spawn(move|| { + spawn(move || { match disclosed_proof::get_state(proof_handle) { Ok(s) => { trace!("vcx_disclosed_proof_get_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, error_string(0), s, source_id); + command_handle, error::SUCCESS.message, s, source_id); cb(command_handle, error::SUCCESS.code_num, s) - }, + } Err(e) => { error!("vcx_disclosed_proof_get_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, error_string(e), 0, source_id); - cb(command_handle, e, 0) + command_handle, e, 0, source_id); + cb(command_handle, e.into(), 0) } }; @@ -286,27 +279,27 @@ pub extern fn vcx_disclosed_proof_update_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_update_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", - command_handle, proof_handle, source_id); + command_handle, proof_handle, source_id); - spawn(move|| { + spawn(move || { match disclosed_proof::update_state(proof_handle) { Ok(s) => { trace!("vcx_disclosed_proof_update_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, error_string(0), s, source_id); + command_handle, error::SUCCESS.message, s, source_id); cb(command_handle, error::SUCCESS.code_num, s) - }, + } Err(e) => { error!("vcx_disclosed_proof_update_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, error_string(e), 0, source_id); - cb(command_handle, e, 0) + command_handle, e, 0, source_id); + cb(command_handle, e.into(), 0) } }; @@ -333,29 +326,29 @@ pub extern fn vcx_disclosed_proof_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", - command_handle, proof_handle, source_id); + command_handle, proof_handle, source_id); - spawn(move|| { + spawn(move || { match disclosed_proof::to_string(proof_handle) { Ok(x) => { trace!("vcx_disclosed_proof_serialize_cb(command_handle: {}, rc: {}, data: {}) source_id: {}", - command_handle, error_string(0), x, source_id); + command_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); - cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); - }, + cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); + } Err(x) => { error!("vcx_disclosed_proof_serialize_cb(command_handle: {}, rc: {}, data: {}) source_id: {}", - command_handle, error_string(x), 0, source_id); - cb(command_handle,x,ptr::null_mut()); - }, + command_handle, x, 0, source_id); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -382,25 +375,25 @@ pub extern fn vcx_disclosed_proof_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(proof_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(proof_data, VcxErrorKind::InvalidOption); trace!("vcx_disclosed_proof_deserialize(command_handle: {}, proof_data: {})", - command_handle, proof_data); + command_handle, proof_data); - spawn(move|| { + spawn(move || { match disclosed_proof::from_string(&proof_data) { Ok(x) => { trace!("vcx_disclosed_proof_deserialize_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", - command_handle, error_string(0), x, disclosed_proof::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, disclosed_proof::get_source_id(x).unwrap_or_default()); cb(command_handle, 0, x); - }, + } Err(x) => { error!("vcx_disclosed_proof_deserialize_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, ""); - cb(command_handle, x.to_error_code(), 0); - }, + command_handle, x, 0, ""); + cb(command_handle, x.into(), 0); + } }; Ok(()) @@ -426,29 +419,29 @@ pub extern fn vcx_disclosed_proof_retrieve_credentials(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_retrieve_credentials >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, proof_handle: {}) source_id: {}", - command_handle, proof_handle, source_id); + command_handle, proof_handle, source_id); - spawn(move|| { + spawn(move || { match disclosed_proof::retrieve_credentials(proof_handle) { Ok(x) => { trace!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, rc: {}, data: {}) source_id: {}", - command_handle, error_string(0), x, source_id); + command_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); - cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); - }, + cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); + } Err(x) => { error!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, rc: {}, data: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, source_id); - cb(command_handle,x.to_error_code(),ptr::null_mut()); - }, + command_handle, x, 0, source_id); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -505,30 +498,30 @@ pub extern fn vcx_disclosed_proof_generate_proof(command_handle: u32, cb: Option) -> u32 { info!("vcx_disclosed_proof_generate_proof >>>"); - check_useful_c_str!(selected_credentials, error::INVALID_OPTION.code_num); - check_useful_c_str!(self_attested_attrs, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(selected_credentials, VcxErrorKind::InvalidOption); + check_useful_c_str!(self_attested_attrs, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !disclosed_proof::is_valid_handle(proof_handle) { - return error::INVALID_DISCLOSED_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle).into() } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_disclosed_proof_generate_proof(command_handle: {}, proof_handle: {}, selected_credentials: {}, self_attested_attrs: {}) source_id: {}", - command_handle, proof_handle, selected_credentials, self_attested_attrs, source_id); + command_handle, proof_handle, selected_credentials, self_attested_attrs, source_id); - spawn(move|| { + spawn(move || { match disclosed_proof::generate_proof(proof_handle, selected_credentials, self_attested_attrs) { Ok(_) => { trace!("vcx_disclosed_proof_generate_proof(command_handle: {}, rc: {}) source_id: {}", - command_handle, error::SUCCESS.code_num, source_id); + command_handle, error::SUCCESS.message, source_id); cb(command_handle, error::SUCCESS.code_num); - }, + } Err(x) => { error!("vcx_disclosed_proof_generate_proof(command_handle: {}, rc: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), source_id); - cb(command_handle,x.to_error_code()); - }, + command_handle, x, source_id); + cb(command_handle, x.into()); + } }; Ok(()) @@ -551,23 +544,23 @@ pub extern fn vcx_disclosed_proof_release(handle: u32) -> u32 { let source_id = disclosed_proof::get_source_id(handle).unwrap_or_default(); match disclosed_proof::release(handle) { - Ok(_) => { - let success_err_code = error::SUCCESS.code_num; + Ok(_) => { trace!("vcx_disclosed_proof_release(handle: {}, rc: {}), source_id: {:?}", - handle, error_string(success_err_code), source_id); - success_err_code - }, + handle, error::SUCCESS.message, source_id); + error::SUCCESS.code_num + } Err(e) => { error!("vcx_disclosed_proof_release(handle: {}, rc: {}), source_id: {:?}", - handle, error_string(e), source_id); - e - }, + handle, e, source_id); + e.into() + } } } #[cfg(test)] mod tests { extern crate serde_json; + use super::*; use std::ffi::CString; use std::time::Duration; @@ -584,9 +577,9 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_disclosed_proof_create_with_request(cb.command_handle, - CString::new("test_create").unwrap().into_raw(), - CString::new(::utils::constants::PROOF_REQUEST_JSON).unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new("test_create").unwrap().into_raw(), + CString::new(::utils::constants::PROOF_REQUEST_JSON).unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); assert!(cb.receive(Some(Duration::from_secs(10))).unwrap() > 0); } @@ -598,7 +591,7 @@ mod tests { cb.command_handle, CString::new("test_create").unwrap().into_raw(), CString::new(BAD_PROOF_REQUEST).unwrap().into_raw(), - Some(cb.get_callback())),error::SUCCESS.code_num); + Some(cb.get_callback())), error::SUCCESS.code_num); assert_eq!(cb.receive(Some(Duration::from_secs(10))).err(), Some(error::INVALID_JSON.code_num)); } @@ -621,23 +614,22 @@ mod tests { fn test_vcx_disclosed_proof_release() { init!("true"); let cb = return_types_u32::Return_U32_STR::new().unwrap(); - let handle = disclosed_proof::create_proof("1",::utils::constants::PROOF_REQUEST_JSON).unwrap(); + let handle = disclosed_proof::create_proof("1", ::utils::constants::PROOF_REQUEST_JSON).unwrap(); let unknown_handle = handle + 1; let err = vcx_disclosed_proof_release(unknown_handle); assert_eq!(err, error::INVALID_DISCLOSED_PROOF_HANDLE.code_num); - } #[test] fn test_vcx_disclosed_proof_serialize_and_deserialize() { init!("true"); let cb = return_types_u32::Return_U32_STR::new().unwrap(); - let handle = disclosed_proof::create_proof("1",::utils::constants::PROOF_REQUEST_JSON).unwrap(); + let handle = disclosed_proof::create_proof("1", ::utils::constants::PROOF_REQUEST_JSON).unwrap(); assert_eq!(vcx_disclosed_proof_serialize(cb.command_handle, - handle, - Some(cb.get_callback())), error::SUCCESS.code_num); + handle, + Some(cb.get_callback())), error::SUCCESS.code_num); let s = cb.receive(Some(Duration::from_secs(2))).unwrap().unwrap(); - let j:Value = serde_json::from_str(&s).unwrap(); + let j: Value = serde_json::from_str(&s).unwrap(); assert_eq!(j["version"], DEFAULT_SERIALIZE_VERSION); let cb = return_types_u32::Return_U32_U32::new().unwrap(); @@ -654,33 +646,33 @@ mod tests { fn test_vcx_send_proof() { init!("true"); - let handle = disclosed_proof::create_proof("1",::utils::constants::PROOF_REQUEST_JSON).unwrap(); - assert_eq!(disclosed_proof::get_state(handle).unwrap(),VcxStateType::VcxStateRequestReceived as u32); + let handle = disclosed_proof::create_proof("1", ::utils::constants::PROOF_REQUEST_JSON).unwrap(); + assert_eq!(disclosed_proof::get_state(handle).unwrap(), VcxStateType::VcxStateRequestReceived as u32); let connection_handle = connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32::new().unwrap(); - assert_eq!(vcx_disclosed_proof_send_proof(cb.command_handle,handle,connection_handle,Some(cb.get_callback())), error::SUCCESS.code_num); + assert_eq!(vcx_disclosed_proof_send_proof(cb.command_handle, handle, connection_handle, Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); } #[test] - fn test_vcx_proof_get_requests(){ + fn test_vcx_proof_get_requests() { init!("true"); let cxn = ::connection::tests::build_test_connection(); ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_PROOF_REQUEST_RESPONSE.to_vec()); let cb = return_types_u32::Return_U32_STR::new().unwrap(); - assert_eq!(vcx_disclosed_proof_get_requests(cb.command_handle, cxn, Some(cb.get_callback())),error::SUCCESS.code_num as u32); + assert_eq!(vcx_disclosed_proof_get_requests(cb.command_handle, cxn, Some(cb.get_callback())), error::SUCCESS.code_num as u32); cb.receive(Some(Duration::from_secs(10))).unwrap(); } #[test] fn test_vcx_proof_get_state() { init!("true"); - let handle = disclosed_proof::create_proof("1",::utils::constants::PROOF_REQUEST_JSON).unwrap(); + let handle = disclosed_proof::create_proof("1", ::utils::constants::PROOF_REQUEST_JSON).unwrap(); assert!(handle > 0); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - assert_eq!(vcx_disclosed_proof_get_state(cb.command_handle,handle,Some(cb.get_callback())),error::SUCCESS.code_num); + assert_eq!(vcx_disclosed_proof_get_state(cb.command_handle, handle, Some(cb.get_callback())), error::SUCCESS.code_num); let state = cb.receive(Some(Duration::from_secs(10))).unwrap(); assert_eq!(state, VcxStateType::VcxStateRequestReceived as u32); } diff --git a/vcx/libvcx/src/api/issuer_credential.rs b/vcx/libvcx/src/api/issuer_credential.rs index bc5d8e2644..d6e1d099a8 100644 --- a/vcx/libvcx/src/api/issuer_credential.rs +++ b/vcx/libvcx/src/api/issuer_credential.rs @@ -1,16 +1,13 @@ -extern crate libc; -extern crate serde_json; - -use self::libc::c_char; +use serde_json; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use connection; use settings; use issuer_credential; use std::ptr; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Create a Issuer Credential object that provides a credential for an enterprise's user /// Assumes a credential definition has been written to the ledger. @@ -40,60 +37,60 @@ use utils::threadpool::spawn; #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_issuer_create_credential(command_handle: u32, - source_id: *const c_char, - cred_def_handle: u32, - issuer_did: *const c_char, - credential_data: *const c_char, - credential_name: *const c_char, - price: *const c_char, - cb: Option) -> u32 { + source_id: *const c_char, + cred_def_handle: u32, + issuer_did: *const c_char, + credential_data: *const c_char, + credential_name: *const c_char, + price: *const c_char, + cb: Option) -> u32 { info!("vcx_issuer_create_credential >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); - check_useful_c_str!(credential_name, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(price, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(credential_data, VcxErrorKind::InvalidOption); + check_useful_c_str!(credential_name, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(price, VcxErrorKind::InvalidOption); let issuer_did: String = if !issuer_did.is_null() { - check_useful_c_str!(issuer_did, error::INVALID_OPTION.code_num); + check_useful_c_str!(issuer_did, VcxErrorKind::InvalidOption); issuer_did.to_owned() } else { match settings::get_config_value(settings::CONFIG_INSTITUTION_DID) { Ok(x) => x, - Err(x) => return x + Err(x) => return x.into() } }; let price: u64 = match price.parse::() { Ok(x) => x, - Err(_) => return error::INVALID_OPTION.code_num, + Err(err) => return VcxError::from_msg(VcxErrorKind::InvalidOption, format!("Cannot parse price: {}", err)).into(), }; if !::credential_def::is_valid_handle(cred_def_handle) { - return error::INVALID_CREDENTIAL_DEF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidCredDefHandle).into() } trace!("vcx_issuer_create_credential(command_handle: {}, source_id: {}, cred_def_handle: {}, issuer_did: {}, credential_data: {}, credential_name: {})", - command_handle, - source_id, - cred_def_handle, - issuer_did, - credential_data, - credential_name); - - spawn(move|| { + command_handle, + source_id, + cred_def_handle, + issuer_did, + credential_data, + credential_name); + + spawn(move || { let (rc, handle) = match issuer_credential::issuer_credential_create(cred_def_handle, source_id, issuer_did, credential_name, credential_data, price) { Ok(x) => { trace!("vcx_issuer_create_credential_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), x, issuer_credential::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, issuer_credential::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) - }, + } Err(x) => { warn!("vcx_issuer_create_credential_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, ""); - (x.to_error_code(), 0) - }, + command_handle, x, 0, ""); + (x.into(), 0) + } }; cb(command_handle, rc, handle); @@ -119,40 +116,40 @@ pub extern fn vcx_issuer_create_credential(command_handle: u32, /// Error code as a u32 #[no_mangle] pub extern fn vcx_issuer_send_credential_offer(command_handle: u32, - credential_handle: u32, - connection_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + connection_handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_send_credential_offer >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", - command_handle, credential_handle, connection_handle, source_id); + command_handle, credential_handle, connection_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } - spawn(move|| { + spawn(move || { let err = match issuer_credential::send_credential_offer(credential_handle, connection_handle) { Ok(x) => { trace!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", - command_handle, credential_handle, error_string(x), source_id); + command_handle, credential_handle, error::SUCCESS.message, source_id); x - }, + } Err(x) => { warn!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {})", - command_handle, credential_handle, error_string(x.to_error_code()), source_id); - x.to_error_code() - }, + command_handle, credential_handle, x, source_id); + x.into() + } }; - cb(command_handle,err); + cb(command_handle, err); Ok(()) }); @@ -173,31 +170,31 @@ pub extern fn vcx_issuer_send_credential_offer(command_handle: u32, /// Error code as a u32 #[no_mangle] pub extern fn vcx_issuer_credential_update_state(command_handle: u32, - credential_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_credential_update_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_issuer_credential_update_state(command_handle: {}, credential_handle: {}) source_id: {}", - command_handle, credential_handle, source_id); + command_handle, credential_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } - spawn(move|| { + spawn(move || { match issuer_credential::update_state(credential_handle) { Ok(x) => { trace!("vcx_issuer_credential_update_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, credential_handle, error_string(0), x, source_id); + command_handle, credential_handle, error::SUCCESS.message, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); - }, + } Err(x) => { warn!("vcx_issuer_credential_update_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, credential_handle, x.to_string(), 0, source_id); - cb(command_handle, x.to_error_code(), 0); + command_handle, credential_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); } }; @@ -218,35 +215,34 @@ pub extern fn vcx_issuer_credential_update_state(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_issuer_credential_get_state(command_handle: u32, - credential_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_credential_get_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_issuer_credential_get_state(command_handle: {}, credential_handle: {}) source_id: {}", - command_handle, credential_handle, source_id); + command_handle, credential_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } - spawn(move|| { + spawn(move || { match issuer_credential::get_state(credential_handle) { Ok(x) => { trace!("vcx_issuer_credential_get_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, credential_handle, error_string(0), x, source_id); + command_handle, credential_handle, error::SUCCESS.message, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); - }, + } Err(x) => { warn!("vcx_issuer_credential_get_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, credential_handle, error_string(x), 0, source_id); - cb(command_handle, x, 0); - }, + command_handle, credential_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); + } }; Ok(()) @@ -260,6 +256,7 @@ pub extern fn vcx_issuer_get_credential_request(credential_handle: u32, credenti info!("vcx_issuer_get_credential_request >>>"); error::SUCCESS.code_num } + #[allow(unused_variables, unused_mut)] pub extern fn vcx_issuer_accept_credential(credential_handle: u32) -> u32 { info!("vcx_issuer_accept_credential >>>"); @@ -281,39 +278,39 @@ pub extern fn vcx_issuer_accept_credential(credential_handle: u32) -> u32 { /// Error code as a u32 #[no_mangle] pub extern fn vcx_issuer_send_credential(command_handle: u32, - credential_handle: u32, - connection_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + connection_handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_send_credential >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", - command_handle, credential_handle, connection_handle, source_id); - spawn(move|| { + command_handle, credential_handle, connection_handle, source_id); + spawn(move || { let err = match issuer_credential::send_credential(credential_handle, connection_handle) { Ok(x) => { trace!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", - command_handle, credential_handle, error_string(x), source_id); + command_handle, credential_handle, error::SUCCESS.message, source_id); x - }, + } Err(x) => { warn!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", - command_handle, credential_handle, error_string(x.to_error_code()), source_id); - x.to_error_code() - }, + command_handle, credential_handle, x, source_id); + x.into() + } }; - cb(command_handle,err); + cb(command_handle, err); Ok(()) }); @@ -340,32 +337,32 @@ pub extern fn vcx_issuer_terminate_credential(credential_handle: u32, terminatio /// Error code as a u32 #[no_mangle] pub extern fn vcx_issuer_credential_serialize(command_handle: u32, - credential_handle: u32, - cb: Option) -> u32 { + credential_handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_credential_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); trace!("vcx_issuer_credential_serialize(credential_serialize(command_handle: {}, credential_handle: {}), source_id: {}", - command_handle, credential_handle, source_id); - spawn(move|| { + command_handle, credential_handle, source_id); + spawn(move || { match issuer_credential::to_string(credential_handle) { Ok(x) => { trace!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, credential_handle, error_string(0), x, source_id); + command_handle, credential_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); - cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); - }, + cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); + } Err(x) => { trace!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {})", - command_handle, credential_handle, error_string(x.to_error_code()), "null", source_id); - cb(command_handle,x.to_error_code(),ptr::null_mut()); - }, + command_handle, credential_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -387,27 +384,27 @@ pub extern fn vcx_issuer_credential_serialize(command_handle: u32, /// Error code as a u32 #[no_mangle] pub extern fn vcx_issuer_credential_deserialize(command_handle: u32, - credential_data: *const c_char, - cb: Option) -> u32 { + credential_data: *const c_char, + cb: Option) -> u32 { info!("vcx_issuer_credential_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(credential_data, VcxErrorKind::InvalidOption); trace!("vcx_issuer_credential_deserialize(command_handle: {}, credential_data: {})", command_handle, credential_data); - spawn(move|| { + spawn(move || { let (rc, handle) = match issuer_credential::from_string(&credential_data) { Ok(x) => { trace!("vcx_issuer_credential_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", - command_handle, error_string(0), x, issuer_credential::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, issuer_credential::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) - }, + } Err(x) => { warn!("vcx_issuer_credential_deserialize_cb(command_handle: {}, rc: {}, handle: {})", - command_handle, x.to_string(), 0); - (x.to_error_code(), 0) - }, + command_handle, x, 0); + (x.into(), 0) + } }; cb(command_handle, rc, handle); @@ -432,14 +429,14 @@ pub extern fn vcx_issuer_credential_release(credential_handle: u32) -> u32 { match issuer_credential::release(credential_handle) { Ok(_) => { trace!("(vcx_issuer_credential_release credential_handle: {}, rc: {}), source_id: {}", - credential_handle, error_string(0), source_id); + credential_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num - }, + } Err(e) => { warn!("(vcx_issuer_credential_release credential_handle: {}, rc: {}), source_id: {}", - credential_handle, error_string(e.to_error_code()), source_id); - e.to_error_code() - }, + credential_handle, e, source_id); + e.into() + } } } @@ -463,38 +460,39 @@ pub extern fn vcx_issuer_credential_release(credential_handle: u32) -> u32 { /// } #[no_mangle] pub extern fn vcx_issuer_credential_get_payment_txn(command_handle: u32, - handle: u32, - cb: Option) -> u32 { + handle: u32, + cb: Option) -> u32 { info!("vcx_issuer_credential_get_payment_txn >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = issuer_credential::get_source_id(handle).unwrap_or_default(); trace!("vcx_issuer_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); - spawn(move|| { + spawn(move || { match issuer_credential::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { trace!("vcx_issuer_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}) source_id: {}", - command_handle, error_string(0), x, source_id); + command_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, 0, msg.as_ptr()); } - Err(_) => { + Err(e) => { + let err = VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payment txn: {}", e)); error!("vcx_issuer_credential_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}) source_id: {}", - command_handle, error_string(error::INVALID_JSON.code_num), "null", source_id); - cb(command_handle, error::INVALID_JSON.code_num, ptr::null_mut()); + command_handle, err, "null", source_id); + cb(command_handle, err.into(), ptr::null_mut()); } } - }, + } Err(x) => { error!("vcx_issuer_credential_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}) source_id: {}", - command_handle, x.to_string(), "null", source_id); - cb(command_handle, x.to_error_code(), ptr::null()); - }, + command_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null()); + } }; Ok(()) @@ -518,32 +516,31 @@ pub extern fn vcx_issuer_credential_get_payment_txn(command_handle: u32, pub extern fn vcx_issuer_revoke_credential(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { - - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); if !issuer_credential::is_valid_handle(credential_handle) { - return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle).into() } let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); info!("vcx_issuer_revoke_credential(command_handle: {}, credential_handle: {}) source_id: {}", command_handle, credential_handle, source_id); - spawn(move|| { + spawn(move || { let err = match issuer_credential::revoke_credential(credential_handle) { Ok(_) => { info!("vcx_issuer_revoke_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", - command_handle, credential_handle, error_string(error::SUCCESS.code_num), source_id); + command_handle, credential_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num - }, + } Err(x) => { warn!("vcx_issuer_revoke_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", - command_handle, credential_handle, error_string(x), source_id); - x - }, + command_handle, credential_handle, x, source_id); + x.into() + } }; - cb(command_handle,err); + cb(command_handle, err); Ok(()) }); @@ -554,6 +551,7 @@ pub extern fn vcx_issuer_revoke_credential(command_handle: u32, #[cfg(test)] mod tests { extern crate serde_json; + use super::*; use std::ffi::CString; use std::ptr; @@ -635,13 +633,13 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - ::credential_def::tests::create_cred_def_fake(), - ptr::null(), - CString::new(DEFAULT_ATTR).unwrap().into_raw(), - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new("1").unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), + ptr::null(), + CString::new(DEFAULT_ATTR).unwrap().into_raw(), + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + CString::new("1").unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); } @@ -665,27 +663,28 @@ mod tests { fn create_default_issuer_credential() -> u32 { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - ::credential_def::tests::create_cred_def_fake(), - ptr::null(), - CString::new(DEFAULT_ATTR).unwrap().into_raw(), - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new("1").unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(10))).unwrap() + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), + ptr::null(), + CString::new(DEFAULT_ATTR).unwrap().into_raw(), + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + CString::new("1").unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); + cb.receive(Some(Duration::from_secs(10))).unwrap() } + #[test] fn test_vcx_issuer_credential_serialize_deserialize() { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), ::credential_def::tests::create_cred_def_fake(), - CString::new(DEFAULT_DID).unwrap().into_raw(), - CString::new(DEFAULT_ATTR).unwrap().into_raw(), - CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new("1").unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new(DEFAULT_DID).unwrap().into_raw(), + CString::new(DEFAULT_ATTR).unwrap().into_raw(), + CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), + CString::new("1").unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); let handle = cb.receive(Some(Duration::from_secs(2))).unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); assert_eq!(vcx_issuer_credential_serialize(cb.command_handle, @@ -697,7 +696,7 @@ mod tests { assert_eq!(vcx_issuer_credential_deserialize(cb.command_handle, CString::new(s).unwrap().into_raw(), Some(cb.get_callback())), - error::SUCCESS.code_num); + error::SUCCESS.code_num); let handle = cb.receive(Some(Duration::from_secs(2))).unwrap(); assert!(handle > 0); } @@ -706,10 +705,10 @@ mod tests { fn test_vcx_issuer_send_credential_offer() { init!("true"); let handle = issuer_credential::from_string(DEFAULT_SERIALIZED_ISSUER_CREDENTIAL).unwrap(); - assert_eq!(issuer_credential::get_state(handle).unwrap(),VcxStateType::VcxStateInitialized as u32); + assert_eq!(issuer_credential::get_state(handle).unwrap(), VcxStateType::VcxStateInitialized as u32); let connection_handle = ::connection::tests::build_test_connection(); - connection::connect(connection_handle,None).unwrap(); + connection::connect(connection_handle, None).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_issuer_send_credential_offer(cb.command_handle, @@ -729,7 +728,7 @@ mod tests { // create connection let connection_handle = ::connection::tests::build_test_connection(); - connection::connect(connection_handle,None).unwrap(); + connection::connect(connection_handle, None).unwrap(); // send the credential let cb = return_types_u32::Return_U32::new().unwrap(); @@ -742,7 +741,7 @@ mod tests { } #[test] - fn test_create_credential_arguments_correct(){ + fn test_create_credential_arguments_correct() { init!("true"); settings::set_config_value(settings::CONFIG_INSTITUTION_DID, DEFAULT_DID); let cb = return_types_u32::Return_U32_U32::new().unwrap(); @@ -766,7 +765,7 @@ mod tests { } #[test] - fn test_create_credential_invalid_price(){ + fn test_create_credential_invalid_price() { init!("true"); settings::set_config_value(settings::CONFIG_INSTITUTION_DID, DEFAULT_DID); let cb = return_types_u32::Return_U32_U32::new().unwrap(); @@ -800,7 +799,7 @@ mod tests { init!("false"); //settings::set_defaults(); let credential = issuer_credential::tests::create_standard_issuer_credential(); - let s = credential.to_string(); + let s = credential.to_string().unwrap(); let handle = issuer_credential::from_string(&s).unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); vcx_issuer_credential_get_payment_txn(cb.command_handle, handle, Some(cb.get_callback())); @@ -816,8 +815,8 @@ mod tests { // send the credential let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_issuer_revoke_credential(cb.command_handle, - handle, - Some(cb.get_callback())), + handle, + Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); } diff --git a/vcx/libvcx/src/api/logger.rs b/vcx/libvcx/src/api/logger.rs index 4d24322ef7..8b1e659b06 100644 --- a/vcx/libvcx/src/api/logger.rs +++ b/vcx/libvcx/src/api/logger.rs @@ -1,10 +1,8 @@ -extern crate libc; -extern crate indy_sys; -use utils::logger::{ EnabledCB, FlushCB, LibvcxLogger, LibvcxDefaultLogger, LogCB, LOGGER_STATE, CVoid }; +use libc::c_char; +use utils::logger::{EnabledCB, FlushCB, LibvcxLogger, LibvcxDefaultLogger, LogCB, LOGGER_STATE, CVoid}; use utils::cstring::CStringUtils; -use self::libc::{c_char}; - -use utils::error::{ INVALID_CONFIGURATION, SUCCESS }; +use utils::error::SUCCESS; +use error::prelude::*; /// Set default logger implementation. /// @@ -22,7 +20,7 @@ use utils::error::{ INVALID_CONFIGURATION, SUCCESS }; pub extern fn vcx_set_default_logger(pattern: *const c_char) -> u32 { info!("vcx_set_default_logger >>>"); - check_useful_opt_c_str!(pattern, INVALID_CONFIGURATION.code_num); + check_useful_opt_c_str!(pattern, VcxErrorKind::InvalidConfiguration); trace!("vcx_set_default_logger(pattern: {:?})", pattern); @@ -30,11 +28,11 @@ pub extern fn vcx_set_default_logger(pattern: *const c_char) -> u32 { Ok(_) => { debug!("Logger Successfully Initialized"); SUCCESS.code_num - }, + } Err(ec) => { error!("Logger Failed To Initialize: {}", ec); - ec - }, + ec.into() + } } } @@ -59,17 +57,18 @@ pub extern fn vcx_set_logger(context: *const CVoid, trace!("vcx_set_logger( context: {:?}, enabled: {:?}, log: {:?}, flush: {:?}", context, enabled, log, flush); - check_useful_c_callback!(log, SUCCESS.code_num); + check_useful_c_callback!(log, VcxErrorKind::InvalidOption); + let res = LibvcxLogger::init(context, enabled, log, flush); match res { Ok(_) => { debug!("Logger Successfully Initialized"); SUCCESS.code_num - }, + } Err(ec) => { error!("Logger Failed To Initialize: {}", ec); - ec - }, + ec.into() + } } } @@ -89,9 +88,9 @@ pub extern fn vcx_set_logger(context: *const CVoid, /// This is tested in wrapper tests (python3) #[no_mangle] pub extern fn vcx_get_logger(context_p: *mut *const CVoid, - enabled_cb_p: *mut Option, - log_cb_p: *mut Option, - flush_cb_p: *mut Option) -> u32 { + enabled_cb_p: *mut Option, + log_cb_p: *mut Option, + flush_cb_p: *mut Option) -> u32 { info!("vcx_get_logger >>>"); trace!("vcx_get_logger >>> context_p: {:?}, enabled_cb_p: {:?}, log_cb_p: {:?}, flush_cb_p: {:?}", context_p, enabled_cb_p, log_cb_p, flush_cb_p); diff --git a/vcx/libvcx/src/api/mod.rs b/vcx/libvcx/src/api/mod.rs index 47d34dc6bb..104d2cc97c 100644 --- a/vcx/libvcx/src/api/mod.rs +++ b/vcx/libvcx/src/api/mod.rs @@ -1,5 +1,3 @@ -extern crate libc; - pub mod vcx; pub mod connection; pub mod issuer_credential; @@ -15,13 +13,6 @@ pub mod return_types_u32; use std::fmt; -#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)] -pub enum Errorcode -{ - Success = 0, - Failure = 1, - Waiting = 2, -} /// This macro allows the VcxStateType to be /// serialized within serde as an integer (represented as /// a string, because its still JSON). diff --git a/vcx/libvcx/src/api/proof.rs b/vcx/libvcx/src/api/proof.rs index 984b1ba993..b8d2247c19 100644 --- a/vcx/libvcx/src/api/proof.rs +++ b/vcx/libvcx/src/api/proof.rs @@ -1,14 +1,11 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use proof; use connection; use std::ptr; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Create a new Proof object that requests a proof for an enterprise /// @@ -77,12 +74,12 @@ pub extern fn vcx_proof_create(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_create >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(requested_attrs, error::INVALID_OPTION.code_num); - check_useful_c_str!(requested_predicates, error::INVALID_OPTION.code_num); - check_useful_c_str!(name, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(revocation_interval, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(requested_attrs, VcxErrorKind::InvalidOption); + check_useful_c_str!(requested_predicates, VcxErrorKind::InvalidOption); + check_useful_c_str!(name, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(revocation_interval, VcxErrorKind::InvalidOption); trace!("vcx_proof_create(command_handle: {}, source_id: {}, requested_attrs: {}, requested_predicates: {}, revocation_interval: {}, name: {})", command_handle, source_id, requested_attrs, requested_predicates, revocation_interval, name); @@ -91,13 +88,13 @@ pub extern fn vcx_proof_create(command_handle: u32, let ( rc, handle) = match proof::create_proof(source_id, requested_attrs, requested_predicates, revocation_interval, name) { Ok(x) => { trace!("vcx_proof_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), x, proof::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, proof::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, Err(x) => { warn!("vcx_proof_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, proof::get_source_id(x.to_error_code()).unwrap_or_default()); - (x.to_error_code(), 0) + command_handle, x, 0,x); + (x.into(), 0) }, }; cb(command_handle, rc, handle); @@ -125,27 +122,27 @@ pub extern fn vcx_proof_update_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_update_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { - return error::INVALID_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidProofHandle).into() } spawn(move|| { match proof::update_state(proof_handle) { Ok(x) => { trace!("vcx_proof_update_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", - command_handle, error_string(0), proof_handle, x, source_id); + command_handle, error::SUCCESS.message, proof_handle, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, Err(x) => { warn!("vcx_proof_update_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", - command_handle, x.to_string(), proof_handle, 0, source_id); - cb(command_handle, x.to_error_code(), 0); + command_handle, x, proof_handle, 0, source_id); + cb(command_handle, x.into(), 0); } } @@ -172,27 +169,27 @@ pub extern fn vcx_proof_get_state(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_get_state >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { - return error::INVALID_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidProofHandle).into() } spawn(move|| { match proof::get_state(proof_handle) { Ok(x) => { trace!("vcx_proof_get_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", - command_handle, error_string(0), proof_handle, x, source_id); + command_handle, error::SUCCESS.message, proof_handle, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, Err(x) => { warn!("vcx_proof_get_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", - command_handle, x.to_string(), proof_handle, 0, source_id); - cb(command_handle, x.to_error_code(), 0); + command_handle, x, proof_handle, 0, source_id); + cb(command_handle, x.into(), 0); } } @@ -219,27 +216,27 @@ pub extern fn vcx_proof_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { - return error::INVALID_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidProofHandle).into() }; spawn(move|| { match proof::to_string(proof_handle) { Ok(x) => { trace!("vcx_proof_serialize_cb(command_handle: {}, proof_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, proof_handle, error_string(0), x, source_id); + command_handle, proof_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_proof_serialize_cb(command_handle: {}, proof_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, proof_handle, error_string(x.to_error_code()), "null", source_id); - cb(command_handle, x.to_error_code(), ptr::null_mut()); + command_handle, proof_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); }, }; @@ -266,8 +263,8 @@ pub extern fn vcx_proof_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(proof_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(proof_data, VcxErrorKind::InvalidOption); trace!("vcx_proof_deserialize(command_handle: {}, proof_data: {})", command_handle, proof_data); @@ -276,13 +273,13 @@ pub extern fn vcx_proof_deserialize(command_handle: u32, let (rc, handle) = match proof::from_string(&proof_data) { Ok(x) => { trace!("vcx_proof_deserialize_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), x, proof::get_source_id(x).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, proof::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, Err(x) => { warn!("vcx_proof_deserialize_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, ""); - (x.to_error_code(), 0) + command_handle, x, 0, ""); + (x.into(), 0) }, }; cb(command_handle, rc, handle); @@ -308,13 +305,13 @@ pub extern fn vcx_proof_release(proof_handle: u32) -> u32 { match proof::release(proof_handle) { Ok(_) => { trace!("vcx_proof_release(proof_handle: {}, rc: {}), source_id: {}", - proof_handle, error_string(0), source_id); + proof_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num }, Err(e) => { warn!("vcx_proof_release(proof_handle: {}, rc: {}), source_id: {}", - proof_handle, error_string(e.to_error_code()), source_id); - e.to_error_code() + proof_handle, e, source_id); + e.into() }, } } @@ -339,17 +336,17 @@ pub extern fn vcx_proof_send_request(command_handle: u32, cb: Option) -> u32 { info!("vcx_proof_send_request >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_proof_send_request(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", command_handle, proof_handle, connection_handle, source_id); if !proof::is_valid_handle(proof_handle) { - return error::INVALID_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidProofHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { @@ -361,8 +358,8 @@ pub extern fn vcx_proof_send_request(command_handle: u32, }, Err(x) => { warn!("vcx_proof_send_request_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", - command_handle, x.to_error_code(), proof_handle, source_id); - x.to_error_code() + command_handle, x, proof_handle, source_id); + x.into() }, }; @@ -394,17 +391,17 @@ pub extern fn vcx_get_proof(command_handle: u32, cb: Option) -> u32 { info!("vcx_get_proof >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); trace!("vcx_get_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", command_handle, proof_handle, connection_handle, source_id); if !proof::is_valid_handle(proof_handle) { - return error::INVALID_PROOF_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidProofHandle).into() } if !connection::is_valid_handle(connection_handle) { - return error::INVALID_CONNECTION_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidConnectionHandle).into() } spawn(move|| { @@ -421,8 +418,8 @@ pub extern fn vcx_get_proof(command_handle: u32, cb(command_handle, error::SUCCESS.code_num, proof::get_proof_state(proof_handle).unwrap_or(0), msg.as_ptr()); }, Err(x) => { - warn!("vcx_get_proof_cb(command_handle: {}, proof_handle: {}, rc: {}, proof: {}) source_id: {}", command_handle, proof_handle, x.to_error_code(), "null", source_id); - cb(command_handle, x.to_error_code(), proof::get_proof_state(proof_handle).unwrap_or(0), ptr::null_mut()); + warn!("vcx_get_proof_cb(command_handle: {}, proof_handle: {}, rc: {}, proof: {}) source_id: {}", command_handle, proof_handle, x, "null", source_id); + cb(command_handle, x.into(), proof::get_proof_state(proof_handle).unwrap_or(0), ptr::null_mut()); }, }; diff --git a/vcx/libvcx/src/api/return_types_u32.rs b/vcx/libvcx/src/api/return_types_u32.rs index 2d6460bc93..80296d82da 100644 --- a/vcx/libvcx/src/api/return_types_u32.rs +++ b/vcx/libvcx/src/api/return_types_u32.rs @@ -1,6 +1,4 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use std::sync::mpsc::Receiver; use std::sync::mpsc::RecvTimeoutError; use utils::libindy::next_u32_command_handle; diff --git a/vcx/libvcx/src/api/schema.rs b/vcx/libvcx/src/api/schema.rs index 887084a3e0..dfda960cd5 100644 --- a/vcx/libvcx/src/api/schema.rs +++ b/vcx/libvcx/src/api/schema.rs @@ -1,15 +1,12 @@ -extern crate libc; -extern crate serde_json; - -use self::libc::c_char; +use serde_json; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use std::ptr; use schema; use settings; -use error::ToErrorCode; use utils::threadpool::spawn; +use error::prelude::*; /// Create a new Schema object that can create or look up schemas on the ledger /// @@ -42,38 +39,37 @@ pub extern fn vcx_schema_create(command_handle: u32, cb: Option) -> u32 { info!("vcx_schema_create >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(schema_name, error::INVALID_OPTION.code_num); - check_useful_c_str!(version, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(schema_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(schema_name, VcxErrorKind::InvalidOption); + check_useful_c_str!(version, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(schema_data, VcxErrorKind::InvalidOption); let issuer_did = match settings::get_config_value(settings::CONFIG_INSTITUTION_DID) { Ok(x) => x, - Err(x) => return x + Err(x) => return x.into() }; - trace!(target:"vcx","vcx_schema_create(command_handle: {}, source_id: {}, schema_name: {}, schema_data: {})", - command_handle, source_id, schema_name, schema_data); - - spawn(move|| { - let ( rc, handle) = match schema::create_new_schema(&source_id, - issuer_did, - schema_name, - version, - schema_data) { + trace!(target: "vcx", "vcx_schema_create(command_handle: {}, source_id: {}, schema_name: {}, schema_data: {})", + command_handle, source_id, schema_name, schema_data); + + spawn(move || { + match schema::create_new_schema(&source_id, + issuer_did, + schema_name, + version, + schema_data) { Ok(x) => { - trace!(target:"vcx", "vcx_schema_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(0), x, source_id); - (error::SUCCESS.code_num, x) - }, + trace!(target: "vcx", "vcx_schema_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + command_handle, error::SUCCESS.message, x, source_id); + cb(command_handle, error::SUCCESS.code_num, x); + } Err(x) => { warn!("vcx_schema_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", - command_handle, error_string(x.to_error_code()), 0, source_id); - (x.to_error_code(), 0) }, + command_handle, x, 0, source_id); + cb(command_handle, x.into(), 0); + } }; - cb(command_handle, rc, handle); - Ok(()) }); @@ -98,29 +94,29 @@ pub extern fn vcx_schema_serialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_schema_serialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let source_id = schema::get_source_id(schema_handle).unwrap_or_default(); trace!("vcx_schema_serialize(command_handle: {}, schema_handle: {}) source_id: {}", - command_handle, schema_handle, source_id); + command_handle, schema_handle, source_id); if !schema::is_valid_handle(schema_handle) { - return error::INVALID_SCHEMA_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidSchemaHandle).into() }; - spawn(move|| { + spawn(move || { match schema::to_string(schema_handle) { Ok(x) => { trace!("vcx_schema_serialize_cb(command_handle: {}, schema_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, schema_handle, error_string(0), x, source_id); + command_handle, schema_handle, error::SUCCESS.message, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(x) => { warn!("vcx_schema_serialize_cb(command_handle: {}, schema_handle: {}, rc: {}, state: {}) source_id: {}", - command_handle, schema_handle, error_string(x.to_error_code()), "null", source_id); - cb(command_handle, x.to_error_code(), ptr::null_mut()); - }, + command_handle, schema_handle, x, "null", source_id); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -146,24 +142,23 @@ pub extern fn vcx_schema_deserialize(command_handle: u32, cb: Option) -> u32 { info!("vcx_schema_deserialize >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(schema_data, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(schema_data, VcxErrorKind::InvalidOption); trace!("vcx_schema_deserialize(command_handle: {}, schema_data: {})", command_handle, schema_data); - spawn(move|| { - let (rc, handle) = match schema::from_string(&schema_data) { + spawn(move || { + match schema::from_string(&schema_data) { Ok(x) => { trace!("vcx_schema_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", - command_handle, error_string(0), x, schema::get_source_id(x).unwrap_or_default()); - (error::SUCCESS.code_num, x) - }, + command_handle, error::SUCCESS.message, x, schema::get_source_id(x).unwrap_or_default()); + cb(command_handle, error::SUCCESS.code_num, x); + } Err(x) => { warn!("vcx_schema_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", - command_handle, error_string(x.to_error_code()), 0, ""); - (x.to_error_code(), 0) - }, + command_handle, x, 0, ""); + cb(command_handle, x.into(), 0); + } }; - cb(command_handle, rc, handle); Ok(()) }); @@ -186,13 +181,13 @@ pub extern fn vcx_schema_release(schema_handle: u32) -> u32 { match schema::release(schema_handle) { Ok(_) => { trace!("vcx_schema_release(schema_handle: {}, rc: {}), source_id: {}", - schema_handle, error_string(0), source_id); + schema_handle, error::SUCCESS.message, source_id); error::SUCCESS.code_num - }, + } Err(e) => { warn!("vcx_schema_release(schema_handle: {}, rc: {}), source_id: {}", - schema_handle, error_string(e.to_error_code()), source_id); - e.to_error_code() + schema_handle, e, source_id); + e.into() } } } @@ -212,26 +207,26 @@ pub extern fn vcx_schema_get_schema_id(command_handle: u32, cb: Option) -> u32 { info!("vcx_schema_get_schema_id >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {})", command_handle, schema_handle); if !schema::is_valid_handle(schema_handle) { - return error::INVALID_SCHEMA_HANDLE.code_num; + return VcxError::from(VcxErrorKind::InvalidSchemaHandle).into() } - spawn(move|| { + spawn(move || { match schema::get_schema_id(schema_handle) { Ok(x) => { trace!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {}, rc: {}, schema_seq_no: {})", - command_handle, schema_handle, error_string(0), x); + command_handle, schema_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(x) => { warn!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {}, rc: {}, schema_seq_no: {})", - command_handle, schema_handle, x.to_string(), ""); - cb(command_handle, x.to_error_code(), ptr::null_mut()); - }, + command_handle, schema_handle, x, ""); + cb(command_handle, x.into(), ptr::null_mut()); + } }; Ok(()) @@ -260,27 +255,27 @@ pub extern fn vcx_schema_get_attributes(command_handle: u32, cb: Option) -> u32 { info!("vcx_schema_get_attributes >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - check_useful_c_str!(schema_id, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(source_id, VcxErrorKind::InvalidOption); + check_useful_c_str!(schema_id, VcxErrorKind::InvalidOption); trace!("vcx_schema_get_attributes(command_handle: {}, source_id: {}, schema_id: {})", - command_handle, source_id, schema_id); + command_handle, source_id, schema_id); - spawn(move|| { + spawn(move || { match schema::get_schema_attrs(source_id, schema_id) { Ok((handle, data)) => { - let data:serde_json::Value = serde_json::from_str(&data).unwrap(); + let data: serde_json::Value = serde_json::from_str(&data).unwrap(); let data = data["data"].clone(); trace!("vcx_schema_get_attributes_cb(command_handle: {}, rc: {}, handle: {}, attrs: {})", - command_handle, error_string(0), handle, data); + command_handle, error::SUCCESS.message, handle, data); let msg = CStringUtils::string_to_cstring(data.to_string()); cb(command_handle, error::SUCCESS.code_num, handle, msg.as_ptr()); - }, + } Err(x) => { warn!("vcx_schema_get_attributes_cb(command_handle: {}, rc: {}, handle: {}, attrs: {})", - command_handle, error_string(x.to_error_code()), 0, ""); - cb(command_handle, x.to_error_code(), 0, ptr::null_mut()); - }, + command_handle, x, 0, ""); + cb(command_handle, x.into(), 0, ptr::null_mut()); + } }; Ok(()) @@ -309,37 +304,38 @@ pub extern fn vcx_schema_get_attributes(command_handle: u32, /// } #[no_mangle] pub extern fn vcx_schema_get_payment_txn(command_handle: u32, - handle: u32, - cb: Option) -> u32 { + handle: u32, + cb: Option) -> u32 { info!("vcx_schema_get_payment_txn >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_schema_get_payment_txn(command_handle: {})", command_handle); - spawn(move|| { + spawn(move || { match schema::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { trace!("vcx_schema_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {:?}", - command_handle, error_string(0), x, schema::get_source_id(handle).unwrap_or_default()); + command_handle, error::SUCCESS.message, x, schema::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, 0, msg.as_ptr()); } - Err(_) => { + Err(e) => { + let err = VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payment txn: {}", e)); error!("vcx_schema_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {:?}", - command_handle, error_string(error::INVALID_JSON.code_num), "null", schema::get_source_id(handle).unwrap_or_default()); - cb(command_handle, error::INVALID_JSON.code_num, ptr::null_mut()); + command_handle, err, "null", schema::get_source_id(handle).unwrap_or_default()); + cb(command_handle, err.into(), ptr::null_mut()); } } - }, + } Err(x) => { error!("vcx_schema_get_payment_txn_cb(command_handle: {}, rc: {}, txn: {}), source_id: {:?}", - command_handle, x.to_string(), "null", schema::get_source_id(handle).unwrap_or_default()); - cb(command_handle, x.to_error_code(), ptr::null()); - }, + command_handle, x, "null", schema::get_source_id(handle).unwrap_or_default()); + cb(command_handle, x.into(), ptr::null()); + } }; Ok(()) @@ -361,7 +357,7 @@ mod tests { use std::time::Duration; use settings; #[allow(unused_imports)] - use utils::constants::{ SCHEMA_ID, SCHEMA_WITH_VERSION, DEFAULT_SCHEMA_ATTRS, DEFAULT_SCHEMA_ID, DEFAULT_SCHEMA_NAME }; + use utils::constants::{SCHEMA_ID, SCHEMA_WITH_VERSION, DEFAULT_SCHEMA_ATTRS, DEFAULT_SCHEMA_ID, DEFAULT_SCHEMA_NAME}; use api::return_types_u32; #[test] @@ -369,24 +365,24 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_schema_create(cb.command_handle, - CString::new("Test Source ID").unwrap().into_raw(), - CString::new("Test Schema").unwrap().into_raw(), - CString::new("0.0").unwrap().into_raw(), - CString::new("[att1, att2]").unwrap().into_raw(), - 0, - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new("Test Source ID").unwrap().into_raw(), + CString::new("Test Schema").unwrap().into_raw(), + CString::new("0.0").unwrap().into_raw(), + CString::new("[att1, att2]").unwrap().into_raw(), + 0, + Some(cb.get_callback())), error::SUCCESS.code_num); let handle = cb.receive(Some(Duration::from_secs(2))).unwrap(); - assert!(handle>0) + assert!(handle > 0) } - #[cfg(feature="pool_tests")] + #[cfg(feature = "pool_tests")] #[test] fn test_vcx_create_schema_with_pool() { init!("ledger"); let data = r#"["name","male"]"#; let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); - let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), + let schema_version: String = format!("{}.{}", rand::thread_rng().gen::().to_string(), rand::thread_rng().gen::().to_string()); let cb = return_types_u32::Return_U32_U32::new().unwrap(); @@ -401,7 +397,7 @@ mod tests { let handle = cb.receive(Some(Duration::from_secs(5))).unwrap(); } - #[cfg(feature="pool_tests")] + #[cfg(feature = "pool_tests")] #[test] fn test_vcx_schema_get_attrs_with_pool() { init!("ledger"); @@ -409,9 +405,9 @@ mod tests { let cb = return_types_u32::Return_U32_U32_STR::new().unwrap(); assert_eq!(vcx_schema_get_attributes(cb.command_handle, - CString::new("Test Source ID").unwrap().into_raw(), - CString::new(schema_id).unwrap().into_raw(), - Some(cb.get_callback())), error::SUCCESS.code_num); + CString::new("Test Source ID").unwrap().into_raw(), + CString::new(schema_id).unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); let (err, attrs) = cb.receive(Some(Duration::from_secs(2))).unwrap(); let mut result_vec = vec!(attrs.clone().unwrap()); @@ -439,7 +435,7 @@ mod tests { fn test_vcx_schema_deserialize_succeeds() { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - let err = vcx_schema_deserialize(cb.command_handle,CString::new(SCHEMA_WITH_VERSION).unwrap().into_raw(), Some(cb.get_callback())); + let err = vcx_schema_deserialize(cb.command_handle, CString::new(SCHEMA_WITH_VERSION).unwrap().into_raw(), Some(cb.get_callback())); assert_eq!(err, error::SUCCESS.code_num); let schema_handle = cb.receive(Some(Duration::from_secs(2))).unwrap(); assert!(schema_handle > 0); @@ -462,7 +458,6 @@ mod tests { assert_eq!(vcx_schema_get_schema_id(cb.command_handle, schema_handle, Some(cb.get_callback())), error::SUCCESS.code_num); let id = cb.receive(Some(Duration::from_secs(2))).unwrap().unwrap(); assert_eq!(DEFAULT_SCHEMA_ID, &id); - } #[test] @@ -477,7 +472,7 @@ mod tests { Some(cb.get_callback())), error::SUCCESS.code_num); let (handle, schema_data_as_string) = cb.receive(Some(Duration::from_secs(2))).unwrap(); let schema_data_as_string = schema_data_as_string.unwrap(); - let schema_as_json:serde_json::Value = serde_json::from_str(&schema_data_as_string).unwrap(); + let schema_as_json: serde_json::Value = serde_json::from_str(&schema_data_as_string).unwrap(); assert_eq!(schema_as_json["data"].to_string(), data); } @@ -486,7 +481,7 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32_STR::new().unwrap(); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let handle = schema::create_new_schema("testid", did, "name".to_string(),"1.0".to_string(),"[\"name\":\"male\"]".to_string()).unwrap(); + let handle = schema::create_new_schema("testid", did, "name".to_string(), "1.0".to_string(), "[\"name\":\"male\"]".to_string()).unwrap(); let rc = vcx_schema_get_payment_txn(cb.command_handle, handle, Some(cb.get_callback())); let txn = cb.receive(Some(Duration::from_secs(2))).unwrap(); assert!(txn.is_some()); @@ -497,7 +492,7 @@ mod tests { fn test_vcx_schema_serialize_contains_version() { init!("ledger"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - let schema_name= format!("TestSchema-{}", rand::thread_rng().gen::()); + let schema_name = format!("TestSchema-{}", rand::thread_rng().gen::()); let source_id = "Test Source ID"; assert_eq!(vcx_schema_create(cb.command_handle, CString::new(source_id).unwrap().into_raw(), @@ -515,8 +510,8 @@ mod tests { assert_eq!(vcx_schema_serialize(cb.command_handle, handle, Some(cb.get_callback())), error::SUCCESS.code_num); let data = cb.receive(Some(Duration::from_secs(2))).unwrap().unwrap(); use schema::CreateSchema; - let j:serde_json::Value = serde_json::from_str(&data.clone()).unwrap(); - let schema:CreateSchema = serde_json::from_value(j["data"].clone()).unwrap(); + let j: serde_json::Value = serde_json::from_str(&data.clone()).unwrap(); + let schema: CreateSchema = serde_json::from_value(j["data"].clone()).unwrap(); assert_eq!(j["version"], "1.0"); assert_eq!(schema.get_source_id(), source_id); } @@ -525,7 +520,7 @@ mod tests { fn test_vcx_schema_release() { init!("true"); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let handle = schema::create_new_schema("testid", did, "name".to_string(),"1.0".to_string(),"[\"name\":\"male\"]".to_string()).unwrap(); + let handle = schema::create_new_schema("testid", did, "name".to_string(), "1.0".to_string(), "[\"name\":\"male\"]".to_string()).unwrap(); let unknown_handle = handle + 1; assert_eq!(vcx_schema_release(unknown_handle), error::INVALID_SCHEMA_HANDLE.code_num); } diff --git a/vcx/libvcx/src/api/utils.rs b/vcx/libvcx/src/api/utils.rs index 83916d91c9..6f7349290c 100644 --- a/vcx/libvcx/src/api/utils.rs +++ b/vcx/libvcx/src/api/utils.rs @@ -1,16 +1,14 @@ -extern crate libc; -extern crate serde_json; - -use self::libc::c_char; +use serde_json; +use libc::c_char; use messages; use std::ptr; use utils::httpclient; use utils::constants::*; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; use utils::threadpool::spawn; use std::thread; +use error::prelude::*; #[derive(Deserialize, Debug, Clone)] pub struct UpdateAgentInfo { @@ -26,26 +24,32 @@ pub struct UpdateAgentInfo { /// /// #Returns /// Configuration (wallet also populated), on error returns NULL - #[no_mangle] pub extern fn vcx_provision_agent(config: *const c_char) -> *mut c_char { info!("vcx_provision_agent >>>"); - check_useful_c_str!(config, ptr::null_mut()); + let config = match CStringUtils::c_str_to_string(config) { + Ok(Some(val)) => val, + _ => { + let _res: u32 = VcxError::from_msg(VcxErrorKind::InvalidOption, "Invalid pointer has been passed").into(); + return ptr::null_mut(); + } + }; trace!("vcx_provision_agent(config: {})", config); match messages::agent_utils::connect_register_provision(&config) { Err(e) => { error!("Provision Agent Error {}.", e); + let _res: u32 = e.into(); return ptr::null_mut(); - }, + } Ok(s) => { debug!("Provision Agent Successful"); let msg = CStringUtils::string_to_cstring(s); msg.into_raw() - }, + } } } @@ -61,31 +65,30 @@ pub extern fn vcx_provision_agent(config: *const c_char) -> *mut c_char { /// /// #Returns /// Configuration (wallet also populated), on error returns NULL - #[no_mangle] -pub extern fn vcx_agent_provision_async(command_handle : u32, - config: *const c_char, - cb: Option) -> u32 { +pub extern fn vcx_agent_provision_async(command_handle: u32, + config: *const c_char, + cb: Option) -> u32 { info!("vcx_agent_provision_async >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(config, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(config, VcxErrorKind::InvalidOption); trace!("vcx_agent_provision_async(command_handle: {}, json: {})", - command_handle, config); + command_handle, config); - thread::spawn(move|| { + thread::spawn(move || { match messages::agent_utils::connect_register_provision(&config) { Err(e) => { - error!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: NULL", command_handle, error_string(e)); - cb(command_handle, e, ptr::null_mut()); - }, + error!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: NULL", command_handle, e); + cb(command_handle, e.into(), ptr::null_mut()); + } Ok(s) => { trace!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: {})", - command_handle, error_string(0), s); + command_handle, error::SUCCESS.message, s); let msg = CStringUtils::string_to_cstring(s); cb(command_handle, 0, msg.as_ptr()); - }, + } } }); @@ -103,38 +106,37 @@ pub extern fn vcx_agent_provision_async(command_handle : u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_agent_update_info(command_handle: u32, json: *const c_char, cb: Option) -> u32 { info!("vcx_agent_update_info >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(json, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(json, VcxErrorKind::InvalidOption); trace!("vcx_agent_update_info(command_handle: {}, json: {})", - command_handle, json); + command_handle, json); let agent_info: UpdateAgentInfo = match serde_json::from_str(&json) { Ok(x) => x, - Err(x) => { - return error::INVALID_OPTION.code_num - }, + Err(e) => { + return VcxError::from_msg(VcxErrorKind::InvalidOption, format!("Cannot deserialize agent info: {}", e)).into(); + } }; - spawn(move|| { - match messages::agent_utils::update_agent_info(&agent_info.id, &agent_info.value){ + spawn(move || { + match messages::agent_utils::update_agent_info(&agent_info.id, &agent_info.value) { Ok(x) => { trace!("vcx_agent_update_info_cb(command_handle: {}, rc: {})", - command_handle, error::error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); - }, + } Err(e) => { error!("vcx_agent_update_info_cb(command_handle: {}, rc: {})", - command_handle, error::error_string(e)); - cb(command_handle, e); - }, + command_handle, e); + cb(command_handle, e.into()); + } }; Ok(()) @@ -152,31 +154,30 @@ pub extern fn vcx_agent_update_info(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_ledger_get_fees(command_handle: u32, cb: Option) -> u32 { info!("vcx_ledger_get_fees >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_ledger_get_fees(command_handle: {})", - command_handle); + command_handle); - spawn(move|| { + spawn(move || { match ::utils::libindy::payments::get_ledger_fees() { Ok(x) => { trace!("vcx_ledger_get_fees_cb(command_handle: {}, rc: {}, fees: {})", - command_handle, error::error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, + } Err(e) => { warn!("vcx_ledget_get_fees_cb(command_handle: {}, rc: {}, fees: {})", - command_handle, error_string(e), "null"); + command_handle, e, "null"); - cb(command_handle, e, ptr::null_mut()); - }, + cb(command_handle, e.into(), ptr::null_mut()); + } }; Ok(()) @@ -218,7 +219,6 @@ pub extern fn vcx_set_next_agency_response(message_index: u32) { /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_messages_download(command_handle: u32, message_status: *const c_char, @@ -227,10 +227,10 @@ pub extern fn vcx_messages_download(command_handle: u32, cb: Option) -> u32 { info!("vcx_messages_download >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let message_status = if !message_status.is_null() { - check_useful_c_str!(message_status, error::INVALID_OPTION.code_num); + check_useful_c_str!(message_status, VcxErrorKind::InvalidOption); let v: Vec<&str> = message_status.split(',').collect(); let v = v.iter().map(|s| s.to_string()).collect::>(); Some(v.to_owned()) @@ -239,7 +239,7 @@ pub extern fn vcx_messages_download(command_handle: u32, }; let uids = if !uids.is_null() { - check_useful_c_str!(uids, error::INVALID_OPTION.code_num); + check_useful_c_str!(uids, VcxErrorKind::InvalidOption); let v: Vec<&str> = uids.split(',').collect(); let v = v.iter().map(|s| s.to_string()).collect::>(); Some(v.to_owned()) @@ -248,7 +248,7 @@ pub extern fn vcx_messages_download(command_handle: u32, }; let pw_dids = if !pw_dids.is_null() { - check_useful_c_str!(pw_dids, error::INVALID_OPTION.code_num); + check_useful_c_str!(pw_dids, VcxErrorKind::InvalidOption); let v: Vec<&str> = pw_dids.split(',').collect(); let v = v.iter().map(|s| s.to_string()).collect::>(); Some(v.to_owned()) @@ -257,33 +257,34 @@ pub extern fn vcx_messages_download(command_handle: u32, }; trace!("vcx_messages_download(command_handle: {}, message_status: {:?}, uids: {:?})", - command_handle, message_status, uids); + command_handle, message_status, uids); - spawn(move|| { + spawn(move || { match ::messages::get_message::download_messages(pw_dids, message_status, uids) { Ok(x) => { - match serde_json::to_string(&x) { + match serde_json::to_string(&x) { Ok(x) => { trace!("vcx_messages_download_cb(command_handle: {}, rc: {}, messages: {})", - command_handle, error::error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); - }, - Err(_) => { + } + Err(e) => { + let err = VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize messages: {}", e)); warn!("vcx_messages_download_cb(command_handle: {}, rc: {}, messages: {})", - command_handle, error_string(error::INVALID_JSON.code_num), "null"); + command_handle, err, "null"); - cb(command_handle, error::INVALID_JSON.code_num, ptr::null_mut()); - }, + cb(command_handle, err.into(), ptr::null_mut()); + } }; - }, + } Err(e) => { warn!("vcx_messages_download_cb(command_handle: {}, rc: {}, messages: {})", - command_handle, error_string(e), "null"); + command_handle, e, "null"); - cb(command_handle, e, ptr::null_mut()); - }, + cb(command_handle, e.into(), ptr::null_mut()); + } }; Ok(()) @@ -306,7 +307,6 @@ pub extern fn vcx_messages_download(command_handle: u32, /// /// #Returns /// Error code as a u32 - #[no_mangle] pub extern fn vcx_messages_update_status(command_handle: u32, message_status: *const c_char, @@ -314,27 +314,27 @@ pub extern fn vcx_messages_update_status(command_handle: u32, cb: Option) -> u32 { info!("vcx_messages_update_status >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(message_status, error::INVALID_OPTION.code_num); - check_useful_c_str!(msg_json, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(message_status, VcxErrorKind::InvalidOption); + check_useful_c_str!(msg_json, VcxErrorKind::InvalidOption); trace!("vcx_messages_set_status(command_handle: {}, message_status: {:?}, uids: {:?})", - command_handle, message_status, msg_json); + command_handle, message_status, msg_json); - spawn(move|| { + spawn(move || { match ::messages::update_message::update_agency_messages(&message_status, &msg_json) { Ok(_) => { trace!("vcx_messages_set_status_cb(command_handle: {}, rc: {})", - command_handle, error::error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); - }, + } Err(e) => { warn!("vcx_messages_set_status_cb(command_handle: {}, rc: {})", - command_handle, error_string(e)); + command_handle, e); - cb(command_handle, e); - }, + cb(command_handle, e.into()); + } }; Ok(()) @@ -345,7 +345,6 @@ pub extern fn vcx_messages_update_status(command_handle: u32, #[cfg(test)] mod tests { - use super::*; use std::ffi::CString; use std::time::Duration; @@ -356,12 +355,12 @@ mod tests { fn test_provision_agent() { init!("true"); - let json_string = r#"{"agency_url":"https://enym-eagency.pdev.evernym.com","agency_did":"Ab8TvZa3Q19VNkQVzAWVL7","agency_verkey":"5LXaR43B1aQyeh94VBP8LG1Sgvjk7aNfqiksBCSjwqbf","wallet_name":"test_provision_agent","agent_seed":null,"enterprise_seed":null,"wallet_key":null}"#; + let json_string = r#"{"agency_url":"https://enym-eagency.pdev.evernym.com","agency_did":"Ab8TvZa3Q19VNkQVzAWVL7","agency_verkey":"5LXaR43B1aQyeh94VBP8LG1Sgvjk7aNfqiksBCSjwqbf","wallet_name":"test_provision_agent","agent_seed":null,"enterprise_seed":null,"wallet_key":"key"}"#; let c_json = CString::new(json_string).unwrap().into_raw(); let result = vcx_provision_agent(c_json); + let result = CStringUtils::c_str_to_string(result).unwrap().unwrap(); - check_useful_c_str!(result,()); assert!(result.len() > 0); } @@ -476,3 +475,4 @@ mod tests { cb.receive(Some(Duration::from_secs(10))).unwrap(); } } + diff --git a/vcx/libvcx/src/api/vcx.rs b/vcx/libvcx/src/api/vcx.rs index 4430abedba..e517db788a 100644 --- a/vcx/libvcx/src/api/vcx.rs +++ b/vcx/libvcx/src/api/vcx.rs @@ -1,15 +1,12 @@ -extern crate libc; -extern crate serde_json; - use utils::version_constants; -use self::libc::c_char; +use libc::c_char; use utils::cstring::CStringUtils; use utils::libindy::{wallet, pool}; use utils::error; use settings; use std::ffi::CString; use utils::threadpool::spawn; - +use error::prelude::*; /// Initializes VCX with config settings /// @@ -27,24 +24,24 @@ use utils::threadpool::spawn; #[no_mangle] pub extern fn vcx_init_with_config(command_handle: u32, config: *const c_char, - cb: Option) -> u32 { + cb: Option) -> u32 { info!("vcx_init_with_config >>>"); - check_useful_c_str!(config,error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(config,VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_init(command_handle: {}, config: {:?})", command_handle, config); if config == "ENABLE_TEST_MODE" { - settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"true"); + settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "true"); settings::set_defaults(); } else { match settings::process_config_string(&config) { Err(e) => { error!("Invalid configuration specified: {}", e); - return e; - }, + return e.into(); + } Ok(_) => (), } }; @@ -66,53 +63,52 @@ pub extern fn vcx_init_with_config(command_handle: u32, /// #Returns /// Error code as a u32 #[no_mangle] -pub extern fn vcx_init (command_handle: u32, - config_path:*const c_char, - cb: Option) -> u32 { +pub extern fn vcx_init(command_handle: u32, + config_path: *const c_char, + cb: Option) -> u32 { info!("vcx_init >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_init(command_handle: {}, config_path: {:?})", command_handle, config_path); if !config_path.is_null() { - check_useful_c_str!(config_path,error::INVALID_OPTION.code_num); + check_useful_c_str!(config_path,VcxErrorKind::InvalidOption); if config_path == "ENABLE_TEST_MODE" { - settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"true"); + settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "true"); settings::set_defaults(); } else { match settings::process_config_file(&config_path) { Err(e) => { - return error::INVALID_CONFIGURATION.code_num; - }, + return VcxError::from_msg(VcxErrorKind::InvalidConfiguration, "Cannot initialize with given config path.").into(); + } Ok(_) => { match settings::validate_payment_method() { Ok(_) => (), - Err(e) => return e + Err(e) => return e.into() } - }, + } }; } } else { error!("Cannot initialize with given config path: config path is null."); - return error::INVALID_CONFIGURATION.code_num; + return VcxError::from_msg(VcxErrorKind::InvalidConfiguration, "Cannot initialize with given config path: config path is null.").into(); } _finish_init(command_handle, cb) } fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u32)) -> u32 { - ::utils::threadpool::init(); settings::log_settings(); if wallet::get_wallet_handle() > 0 { error!("Library was already initialized"); - return error::ALREADY_INITIALIZED.code_num; + return VcxError::from_msg(VcxErrorKind::AlreadyInitialized, "Library was already initialized").into(); } // Wallet name was already validated let wallet_name = match settings::get_config_value(settings::CONFIG_WALLET_NAME) { @@ -130,26 +126,26 @@ fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u3 trace!("libvcx version: {}{}", version_constants::VERSION, version_constants::REVISION); - spawn(move|| { + spawn(move || { if settings::get_config_value(settings::CONFIG_GENESIS_PATH).is_ok() { match ::utils::libindy::init_pool() { Ok(_) => (), Err(e) => { error!("Init Pool Error {}.", e); - return Ok(cb(command_handle, e)) - }, + return Ok(cb(command_handle, e.into())); + } } } - match wallet::open_wallet(&wallet_name, wallet_type.as_ref().map(String::as_str), - storage_config.as_ref().map(String::as_str), storage_creds.as_ref().map(String::as_str)) { + match wallet::open_wallet(&wallet_name, wallet_type.as_ref().map(String::as_str), + storage_config.as_ref().map(String::as_str), storage_creds.as_ref().map(String::as_str)) { Ok(_) => { debug!("Init Wallet Successful"); cb(command_handle, error::SUCCESS.code_num); - }, + } Err(e) => { error!("Init Wallet Error {}.", e); - cb(command_handle, e); + cb(command_handle, e.into()); } } Ok(()) @@ -158,7 +154,7 @@ fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u3 error::SUCCESS.code_num } -lazy_static!{ +lazy_static! { pub static ref VERSION_STRING: CString = CString::new(format!("{}{}", version_constants::VERSION, version_constants::REVISION)).unwrap(); } @@ -183,13 +179,13 @@ pub extern fn vcx_shutdown(delete: bool) -> u32 { trace!("vcx_shutdown(delete: {})", delete); match wallet::close_wallet() { - Ok(_) => {}, - Err(_) => {}, + Ok(_) => {} + Err(_) => {} }; match pool::close() { - Ok(_) => {}, - Err(_) => {}, + Ok(_) => {} + Err(_) => {} }; ::schema::release_all(); @@ -236,8 +232,8 @@ pub extern fn vcx_error_c_message(error_code: u32) -> *const c_char { pub extern fn vcx_update_institution_info(name: *const c_char, logo_url: *const c_char) -> u32 { info!("vcx_update_institution_info >>>"); - check_useful_c_str!(name, error::INVALID_CONFIGURATION.code_num); - check_useful_c_str!(logo_url, error::INVALID_CONFIGURATION.code_num); + check_useful_c_str!(name, VcxErrorKind::InvalidConfiguration); + check_useful_c_str!(logo_url, VcxErrorKind::InvalidConfiguration); trace!("vcx_update_institution_info(name: {}, logo_url: {})", name, logo_url); settings::set_config_value(::settings::CONFIG_INSTITUTION_NAME, &name); @@ -250,19 +246,22 @@ pub extern fn vcx_update_institution_info(name: *const c_char, logo_url: *const pub extern fn vcx_mint_tokens(seed: *const c_char, fees: *const c_char) { info!("vcx_mint_tokens >>>"); + // TODO: CHEC let seed = if !seed.is_null() { - check_useful_opt_c_str!(seed, ()); - seed.to_owned() - } - else { + match CStringUtils::c_str_to_string(seed) { + Ok(opt_val) => opt_val.map(String::from), + Err(_) => return () + } + } else { None }; let fees = if !fees.is_null() { - check_useful_opt_c_str!(fees, ()); - fees.to_owned() - } - else { + match CStringUtils::c_str_to_string(fees) { + Ok(opt_val) => opt_val.map(String::from), + Err(_) => return () + } + } else { None }; trace!("vcx_mint_tokens(seed: {:?}, fees: {:?})", seed, fees); @@ -270,17 +269,44 @@ pub extern fn vcx_mint_tokens(seed: *const c_char, fees: *const c_char) { ::utils::libindy::payments::mint_tokens_and_set_fees(None, None, fees, seed).unwrap_or_default(); } +/// Get details for last occurred error. +/// +/// This function should be called in two places to handle both cases of error occurrence: +/// 1) synchronous - in the same application thread +/// 2) asynchronous - inside of function callback +/// +/// NOTE: Error is stored until the next one occurs in the same execution thread or until asynchronous callback finished. +/// Returning pointer has the same lifetime. +/// +/// #Params +/// * `error_json_p` - Reference that will contain error details (if any error has occurred before) +/// in the format: +/// { +/// "backtrace": Optional - error backtrace. +/// Collecting of backtrace can be enabled by setting environment variable `RUST_BACKTRACE=1` +/// "message": str - human-readable error description +/// } +/// +#[no_mangle] +pub extern fn vcx_get_current_error(error_json_p: *mut *const c_char) { + trace!("vcx_get_current_error >>> error_json_p: {:?}", error_json_p); + + let error = get_current_error_c_json(); + unsafe { *error_json_p = error }; + + trace!("vcx_get_current_error: <<<"); +} + #[cfg(test)] mod tests { - use super::*; use std::time::Duration; use std::ptr; use std::thread; use utils::{ libindy::{ - wallet::{import, tests::export_test_wallet, tests::delete_import_wallet_path}, - pool::get_pool_handle + wallet::{import, tests::export_test_wallet, tests::delete_import_wallet_path}, + pool::get_pool_handle }, get_temp_dir_path }; @@ -357,8 +383,8 @@ mod tests { let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init_with_config(cb.command_handle, - CString::new(content).unwrap().into_raw(), - Some(cb.get_callback())), + CString::new(content).unwrap().into_raw(), + Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); // Assert pool was initialized @@ -372,8 +398,8 @@ mod tests { vcx_shutdown(true); use std::fs; use std::io::Write; - settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"false"); - settings::set_config_value(settings::CONFIG_WALLET_KEY,settings::DEFAULT_WALLET_KEY); + settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); + settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); // Write invalid genesis.txn let mut f = fs::File::create(get_temp_dir_path(Some(::utils::constants::GENESIS_PATH)).to_str().unwrap()).unwrap(); @@ -394,7 +420,7 @@ mod tests { let rc = cb.receive(Some(Duration::from_secs(10))); thread::sleep(Duration::from_secs(1)); assert!(rc.is_err()); - assert_eq!(get_pool_handle(), Err(error::NO_POOL_OPEN.code_num)); + assert_eq!(get_pool_handle().unwrap_err().kind(), VcxErrorKind::NoPoolOpen); assert_eq!(wallet::get_wallet_handle(), 0); wallet::delete_wallet(wallet_name, None, None, None).unwrap(); } @@ -520,7 +546,7 @@ mod tests { //Verify shutdown was successful vcx_shutdown(true); - assert_eq!(settings::get_config_value("wallet_name"), Err(error::INVALID_CONFIGURATION.code_num)); + assert_eq!(settings::get_config_value("wallet_name").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); // Init for the second time works ::utils::devsetup::tests::setup_ledger_env(); @@ -549,8 +575,8 @@ mod tests { let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init(cb.command_handle, - CString::new(config_path).unwrap().into_raw(), - Some(cb.get_callback())), + CString::new(config_path).unwrap().into_raw(), + Some(cb.get_callback())), error::ALREADY_INITIALIZED.code_num); } @@ -621,7 +647,7 @@ mod tests { assert_eq!(cb.receive(Some(Duration::from_secs(10))).err(), Some(error::WALLET_NOT_FOUND.code_num)); delete_import_wallet_path(export_path); - settings::set_config_value(settings::CONFIG_WALLET_NAME,settings::DEFAULT_WALLET_NAME); + settings::set_config_value(settings::CONFIG_WALLET_NAME, settings::DEFAULT_WALLET_NAME); vcx_shutdown(true); } @@ -653,7 +679,7 @@ mod tests { settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); - assert_eq!(import(&import_config), Err(::error::wallet::WalletError::CommonError(error::WALLET_ALREADY_EXISTS.code_num))); + assert_eq!(import(&import_config).unwrap_err().kind(), VcxErrorKind::DuplicationWallet); delete_import_wallet_path(export_path); vcx_shutdown(true); @@ -666,13 +692,13 @@ mod tests { let config_path = ""; let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init(cb.command_handle, - CString::new(config_path).unwrap().into_raw(), - Some(cb.get_callback())), + CString::new(config_path).unwrap().into_raw(), + Some(cb.get_callback())), error::INVALID_OPTION.code_num); match get_pool_handle() { - Ok(h) => {pool::close().unwrap();}, - Err(_) => {}, + Ok(h) => { pool::close().unwrap(); } + Err(_) => {} }; } @@ -682,8 +708,8 @@ mod tests { init!("true"); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init(cb.command_handle, - ptr::null(), - Some(cb.get_callback())), + ptr::null(), + Some(cb.get_callback())), error::INVALID_CONFIGURATION.code_num); } @@ -699,21 +725,21 @@ mod tests { let data = r#"["name","male"]"#; let connection = ::connection::tests::build_test_connection(); - let credentialdef = ::credential_def::create_new_credentialdef("SID".to_string(),"NAME".to_string(),"4fUDR9R7fjwELRvH9JT6HH".to_string(), "id".to_string(), "tag".to_string(),"{}".to_string() ).unwrap(); - let issuer_credential = ::issuer_credential::issuer_credential_create(credentialdef,"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(), 1).unwrap(); - let proof = ::proof::create_proof("1".to_string(),"[]".to_string(), "[]".to_string(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); - let schema = ::schema::create_new_schema("5", "VsKV7grR1BUE29mG2Fm2kX".to_string(),"name".to_string(), "0.1".to_string(), data.to_string()).unwrap(); - let disclosed_proof = ::disclosed_proof::create_proof("id",::utils::constants::PROOF_REQUEST_JSON).unwrap(); + let credentialdef = ::credential_def::create_new_credentialdef("SID".to_string(), "NAME".to_string(), "4fUDR9R7fjwELRvH9JT6HH".to_string(), "id".to_string(), "tag".to_string(), "{}".to_string()).unwrap(); + let issuer_credential = ::issuer_credential::issuer_credential_create(credentialdef, "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), "{\"attr\":\"value\"}".to_owned(), 1).unwrap(); + let proof = ::proof::create_proof("1".to_string(), "[]".to_string(), "[]".to_string(), r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); + let schema = ::schema::create_new_schema("5", "VsKV7grR1BUE29mG2Fm2kX".to_string(), "name".to_string(), "0.1".to_string(), data.to_string()).unwrap(); + let disclosed_proof = ::disclosed_proof::create_proof("id", ::utils::constants::PROOF_REQUEST_JSON).unwrap(); let credential = ::credential::credential_create_with_offer("name", ::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); vcx_shutdown(true); - assert_eq!(::connection::release(connection),Err(::error::connection::ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(::issuer_credential::release(issuer_credential),Err(::error::issuer_cred::IssuerCredError::InvalidHandle())); - assert_eq!(::schema::release(schema).err(),Some(::error::schema::SchemaError::InvalidHandle())); - assert_eq!(::proof::release(proof).err(),Some(::error::proof::ProofError::InvalidHandle())); - assert_eq!(::credential_def::release(credentialdef),Err(::error::cred_def::CredDefError::InvalidHandle())); - assert_eq!(::credential::release(credential), Err(::error::credential::CredentialError::CommonError(error::INVALID_CREDENTIAL_HANDLE.code_num))); - assert_eq!(::disclosed_proof::release(disclosed_proof), Result::Err(error::INVALID_DISCLOSED_PROOF_HANDLE.code_num)); + assert_eq!(::connection::release(connection).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + assert_eq!(::issuer_credential::release(issuer_credential).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); + assert_eq!(::schema::release(schema).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); + assert_eq!(::proof::release(proof).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); + assert_eq!(::credential_def::release(credentialdef).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); + assert_eq!(::credential::release(credential).unwrap_err().kind(), VcxErrorKind::InvalidCredentialHandle); + assert_eq!(::disclosed_proof::release(disclosed_proof).unwrap_err().kind(), VcxErrorKind::InvalidDisclosedProofHandle); assert_eq!(wallet::get_wallet_handle(), 0); } @@ -721,16 +747,16 @@ mod tests { fn test_error_c_message() { init!("true"); let c_message = CStringUtils::c_str_to_string(vcx_error_c_message(0)).unwrap().unwrap(); - assert_eq!(c_message,error::SUCCESS.message); + assert_eq!(c_message, error::SUCCESS.message); let c_message = CStringUtils::c_str_to_string(vcx_error_c_message(1001)).unwrap().unwrap(); - assert_eq!(c_message,error::UNKNOWN_ERROR.message); + assert_eq!(c_message, error::UNKNOWN_ERROR.message); let c_message = CStringUtils::c_str_to_string(vcx_error_c_message(100100)).unwrap().unwrap(); - assert_eq!(c_message,error::UNKNOWN_ERROR.message); + assert_eq!(c_message, error::UNKNOWN_ERROR.message); let c_message = CStringUtils::c_str_to_string(vcx_error_c_message(1021)).unwrap().unwrap(); - assert_eq!(c_message,error::INVALID_ATTRIBUTES_STRUCTURE.message); + assert_eq!(c_message, error::INVALID_ATTRIBUTES_STRUCTURE.message); } #[test] @@ -775,4 +801,36 @@ mod tests { assert_ne!(get_pool_handle().unwrap(), 0); debug!("This statement should log"); } + + #[test] + fn get_current_error_works_for_no_error() { + let mut error_json_p: *const c_char = ptr::null(); + + vcx_get_current_error(&mut error_json_p); + assert_eq!(None, CStringUtils::c_str_to_string(error_json_p).unwrap()); + } + + #[test] + fn get_current_error_works_for_sync_error() { + ::api::utils::vcx_provision_agent(ptr::null()); + + let mut error_json_p: *const c_char = ptr::null(); + vcx_get_current_error(&mut error_json_p); + assert!(CStringUtils::c_str_to_string(error_json_p).unwrap().is_some()); + } + + #[test] + fn get_current_error_works_for_async_error() { + extern fn cb(storage_handle: u32, + err: u32, + config: *const c_char) { + let mut error_json_p: *const c_char = ptr::null(); + vcx_get_current_error(&mut error_json_p); + assert!(CStringUtils::c_str_to_string(error_json_p).unwrap().is_some()); + } + + let config = CString::new("{}").unwrap(); + ::api::utils::vcx_agent_provision_async(0, config.as_ptr(), Some(cb)); + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + } } diff --git a/vcx/libvcx/src/api/wallet.rs b/vcx/libvcx/src/api/wallet.rs index b1015a3cbe..70fa45870c 100644 --- a/vcx/libvcx/src/api/wallet.rs +++ b/vcx/libvcx/src/api/wallet.rs @@ -1,17 +1,13 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use utils::cstring::CStringUtils; use utils::error; -use utils::error::error_string; -use error::ToErrorCode; use utils::libindy::payments::{pay_a_payee, get_wallet_token_info, create_address}; use utils::libindy::wallet::{export, import, get_wallet_handle}; use utils::libindy::wallet; use std::path::Path; use utils::threadpool::spawn; use std::thread; - +use error::prelude::*; /// Get the total balance from all addresses contained in the configured wallet /// @@ -32,7 +28,7 @@ pub extern fn vcx_wallet_get_token_info(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_get_token_info >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_get_token_info(command_handle: {}, payment_handle: {})", command_handle, payment_handle); @@ -40,17 +36,17 @@ pub extern fn vcx_wallet_get_token_info(command_handle: u32, match get_wallet_token_info() { Ok(x) => { trace!("vcx_wallet_get_token_info_cb(command_handle: {}, rc: {}, info: {})", - command_handle, error_string(0), x.to_string()); + command_handle, 0, x); let msg = CStringUtils::string_to_cstring(x.to_string()); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_wallet_get_token_info_cb(command_handle: {}, rc: {}, info: {})", - command_handle, error_string(x), "null"); + command_handle, x, "null"); let msg = CStringUtils::string_to_cstring("".to_string()); - cb(command_handle, x, msg.as_ptr()); + cb(command_handle, x.into(), msg.as_ptr()); }, }; @@ -75,9 +71,9 @@ pub extern fn vcx_wallet_create_payment_address(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_create_payment_address >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); let seed = if !seed.is_null() { - check_useful_opt_c_str!(seed, error::INVALID_OPTION.code_num); + check_useful_opt_c_str!(seed, VcxErrorKind::InvalidOption); seed } else { None @@ -90,17 +86,17 @@ pub extern fn vcx_wallet_create_payment_address(command_handle: u32, match create_address(seed) { Ok(x) => { trace!("vcx_wallet_create_payment_address_cb(command_handle: {}, rc: {}, address: {})", - command_handle, error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { warn!("vcx_wallet_create_payment_address_cb(command_handle: {}, rc: {}, address: {})", - command_handle, error_string(x), "null"); + command_handle, x, "null"); let msg = CStringUtils::string_to_cstring("".to_string()); - cb(command_handle, x, msg.as_ptr()); + cb(command_handle, x.into(), msg.as_ptr()); }, }; @@ -148,11 +144,11 @@ pub extern fn vcx_wallet_add_record(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_add_record >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(value, error::INVALID_OPTION.code_num); - check_useful_c_str!(tags_json, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(value, VcxErrorKind::InvalidOption); + check_useful_c_str!(tags_json, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_add_record(command_handle: {}, type_: {}, id: {}, value: {}, tags_json: {})", command_handle, type_, id, value, tags_json); @@ -161,15 +157,15 @@ pub extern fn vcx_wallet_add_record(command_handle: u32, match wallet::add_record(&type_, &id, &value, Some(&tags_json)) { Ok(x) => { trace!("vcx_wallet_add_record(command_handle: {}, rc: {})", - command_handle, error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { trace!("vcx_wallet_add_record(command_handle: {}, rc: {})", - command_handle, error_string(x)); + command_handle, x); - cb(command_handle, x); + cb(command_handle, x.into()); }, }; @@ -205,10 +201,10 @@ pub extern fn vcx_wallet_update_record_value(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_update_record_value >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(value, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(value, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_update_record_value(command_handle: {}, type_: {}, id: {}, value: {})", command_handle, type_, id, value); @@ -217,15 +213,15 @@ pub extern fn vcx_wallet_update_record_value(command_handle: u32, match wallet::update_record_value(&type_, &id, &value) { Ok(x) => { trace!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", - command_handle, error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { trace!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", - command_handle, error_string(x)); + command_handle, x); - cb(command_handle, x); + cb(command_handle, x.into()); }, }; @@ -261,10 +257,10 @@ pub extern fn vcx_wallet_update_record_tags(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_update_record_tags >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(tags, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(tags, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_update_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", command_handle, type_, id, tags); @@ -304,10 +300,10 @@ pub extern fn vcx_wallet_add_record_tags(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_add_record_tags >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(tags, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(tags, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_add_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", command_handle, type_, id, tags); @@ -346,10 +342,10 @@ pub extern fn vcx_wallet_delete_record_tags(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_delete_record_tags >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(tags, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(tags, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_delete_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", command_handle, type_, id, tags); @@ -387,10 +383,10 @@ pub extern fn vcx_wallet_get_record(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_get_record >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_str!(options_json, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_str!(options_json, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_get_record(command_handle: {}, type_: {}, id: {}, options: {})", command_handle, type_, id, options_json); @@ -399,7 +395,7 @@ pub extern fn vcx_wallet_get_record(command_handle: u32, match wallet::get_record(&type_, &id, &options_json) { Ok(x) => { trace!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", - command_handle, error_string(0), x); + command_handle, error::SUCCESS.message, x); let msg = CStringUtils::string_to_cstring(x); @@ -407,10 +403,10 @@ pub extern fn vcx_wallet_get_record(command_handle: u32, }, Err(x) => { trace!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", - command_handle, error_string(x), "null"); + command_handle, x, "null"); let msg = CStringUtils::string_to_cstring("".to_string()); - cb(command_handle, x, msg.as_ptr()); + cb(command_handle, x.into(), msg.as_ptr()); }, }; @@ -444,9 +440,9 @@ pub extern fn vcx_wallet_delete_record(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_delete_record >>>"); - check_useful_c_str!(type_, error::INVALID_OPTION.code_num); - check_useful_c_str!(id, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(type_, VcxErrorKind::InvalidOption); + check_useful_c_str!(id, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_delete_record(command_handle: {}, type_: {}, id: {})", command_handle, type_, id); @@ -455,15 +451,15 @@ pub extern fn vcx_wallet_delete_record(command_handle: u32, match wallet::delete_record(&type_, &id) { Ok(x) => { trace!("vcx_wallet_delete_record(command_handle: {}, rc: {})", - command_handle, error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { trace!("vcx_wallet_delete_record(command_handle: {}, rc: {})", - command_handle, error_string(x)); + command_handle, x); - cb(command_handle, x); + cb(command_handle, x.into()); }, }; @@ -499,13 +495,13 @@ pub extern fn vcx_wallet_send_tokens(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_send_tokens >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(recipient, error::INVALID_OPTION.code_num); - check_useful_c_str!(tokens, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(recipient, VcxErrorKind::InvalidOption); + check_useful_c_str!(tokens, VcxErrorKind::InvalidOption); let tokens: u64 = match tokens.parse::() { Ok(x) => x, - Err(_) => return error::INVALID_OPTION.code_num, + Err(e) => return VcxError::from_msg(VcxErrorKind::InvalidOption, format!("Cannot parse tokens: {}", e)).into(), }; trace!("vcx_wallet_send_tokens(command_handle: {}, payment_handle: {}, tokens: {}, recipient: {})", command_handle, payment_handle, tokens, recipient); @@ -514,15 +510,15 @@ pub extern fn vcx_wallet_send_tokens(command_handle: u32, match pay_a_payee(tokens, &recipient) { Ok((payment, msg)) => { trace!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, receipt: {})", - command_handle, error_string(0), msg); + command_handle, error::SUCCESS.message, msg); let msg = CStringUtils::string_to_cstring(msg); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(e) => { let msg = "Failed to send tokens".to_string(); - trace!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, reciept: {})", command_handle, e.to_error_code(), msg); + trace!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, reciept: {})", command_handle, e, msg); let msg = CStringUtils::string_to_cstring("".to_string()); - cb(command_handle, e.to_error_code(), msg.as_ptr()); + cb(command_handle, e.into(), msg.as_ptr()); }, }; @@ -569,7 +565,7 @@ pub extern fn vcx_wallet_open_search(command_handle: i32, search_handle: i32)>) -> u32 { info!("vcx_wallet_open_search >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); use utils::constants::DEFAULT_SEARCH_HANDLE; spawn(move|| { @@ -608,7 +604,7 @@ pub extern fn vcx_wallet_search_next_records(command_handle: i32, records_json: *const c_char)>) -> u32 { info!("vcx_wallet_search_next_records >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_search_next_records(command_handle: {}, wallet_search_handle: {})", command_handle, wallet_search_handle); @@ -642,13 +638,13 @@ pub extern fn vcx_wallet_close_search(command_handle: u32, cb: Option) -> u32 { info!("vcx_wallet_close_search >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_close_search(command_handle: {}, search_handle: {})", command_handle, search_handle); spawn(move|| { trace!("vcx_wallet_close_search(command_handle: {}, rc: {})", - command_handle, error_string(0)); + command_handle, error::SUCCESS.message); cb(command_handle, error::SUCCESS.code_num); Ok(()) }); @@ -678,9 +674,9 @@ pub extern fn vcx_wallet_export(command_handle: u32, err: u32)>) -> u32 { info!("vcx_wallet_export >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(path, error::INVALID_OPTION.code_num); - check_useful_c_str!(backup_key, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(path, VcxErrorKind::InvalidOption); + check_useful_c_str!(backup_key, VcxErrorKind::InvalidOption); trace!("vcx_wallet_export(command_handle: {}, path: {}, backup_key: ****)", command_handle, path); @@ -696,9 +692,8 @@ pub extern fn vcx_wallet_export(command_handle: u32, cb(command_handle, return_code); } Err(e) => { - let return_code = e.to_error_code(); - warn!("vcx_wallet_export(command_handle: {}, rc: {})", command_handle, return_code); - cb(command_handle, return_code); + warn!("vcx_wallet_export(command_handle: {}, rc: {})", command_handle, e); + cb(command_handle, e.into()); } }; @@ -730,8 +725,8 @@ pub extern fn vcx_wallet_import(command_handle: u32, err: u32)>) -> u32 { info!("vcx_wallet_import >>>"); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - check_useful_c_str!(config, error::INVALID_OPTION.code_num); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); + check_useful_c_str!(config, VcxErrorKind::InvalidOption); trace!("vcx_wallet_import(command_handle: {}, config: ****)", command_handle); @@ -740,14 +735,12 @@ pub extern fn vcx_wallet_import(command_handle: u32, trace!("vcx_wallet_import(command_handle: {}, config: ****)", command_handle); match import(&config) { Ok(_) => { - let return_code = error::SUCCESS.code_num; - trace!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, return_code); - cb(command_handle, return_code); + trace!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, error::SUCCESS.message); + cb(command_handle, error::SUCCESS.code_num); } Err(e) => { - let return_code = e.to_error_code(); - warn!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, return_code); - cb(command_handle, return_code); + warn!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, e); + cb(command_handle, e.into()); } }; }); @@ -774,8 +767,8 @@ pub extern fn vcx_wallet_validate_payment_address(command_handle: i32, cb: Option) -> u32 { info!("vcx_wallet_validate_payment_address >>>"); - check_useful_c_str!(payment_address, error::INVALID_OPTION.code_num); - check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + check_useful_c_str!(payment_address, VcxErrorKind::InvalidOption); + check_useful_c_callback!(cb, VcxErrorKind::InvalidOption); trace!("vcx_wallet_validate_payment_address(command_handle: {}, payment_address: {})", command_handle, payment_address); diff --git a/vcx/libvcx/src/connection.rs b/vcx/libvcx/src/connection.rs index 591d53e8fc..7a0f7eb3e2 100644 --- a/vcx/libvcx/src/connection.rs +++ b/vcx/libvcx/src/connection.rs @@ -1,27 +1,22 @@ -extern crate rand; -extern crate serde_json; -extern crate rmp_serde; -extern crate serde; -extern crate libc; +use serde_json; +use serde_json::Value; +use rmp_serde; -use utils::error; -use utils::libindy::signus::create_and_store_my_did; -use utils::libindy::crypto; -use utils::json::mapped_key_rewrite; use api::VcxStateType; use settings; -use messages::GeneralMessage; use messages; -use messages::{MessageStatusCode, RemoteMessageType}; +use messages::{GeneralMessage, MessageStatusCode, RemoteMessageType, ObjectWithVersion}; use messages::invite::{InviteDetail, SenderDetail, Payload as ConnectionPayload, AcceptanceDetails}; use messages::payload::{Payloads, Thread}; use messages::get_message::Message; -use serde_json::Value; -use utils::json::KeyMatch; -use error::connection::ConnectionError; -use error::ToErrorCode; use object_cache::ObjectCache; +use error::prelude::*; +use utils::error; +use utils::libindy::signus::create_and_store_my_did; +use utils::libindy::crypto; +use utils::json::mapped_key_rewrite; use utils::constants::DEFAULT_SERIALIZE_VERSION; +use utils::json::KeyMatch; use std::collections::HashMap; lazy_static! { @@ -47,7 +42,7 @@ impl Default for ConnectionOptions { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] struct Connection { source_id: String, pw_did: String, @@ -69,7 +64,7 @@ struct Connection { impl Connection { - fn _connect_send_invite(&mut self, options: &ConnectionOptions) -> Result { + fn _connect_send_invite(&mut self, options: &ConnectionOptions) -> VcxResult { debug!("sending invite for connection {}", self.source_id); let (invite, url) = @@ -81,7 +76,8 @@ impl Connection { .agent_vk(&self.agent_vk)? .public_did(self.public_did.as_ref().map(String::as_str))? .thread(&Thread::new())? - .send_secure()?; + .send_secure() + .map_err(|err| err.extend("Cannot send invite"))?; self.state = VcxStateType::VcxStateOfferSent; self.invite_detail = Some(invite); @@ -90,7 +86,7 @@ impl Connection { Ok(error::SUCCESS.code_num) } - pub fn delete_connection(&mut self) -> Result { + pub fn delete_connection(&mut self) -> VcxResult { trace!("Connection::delete_connection >>>"); messages::delete_connection() @@ -98,23 +94,19 @@ impl Connection { .to_vk(&self.pw_verkey)? .agent_did(&self.agent_did)? .agent_vk(&self.agent_vk)? - .send_secure()?; + .send_secure() + .map_err(|err| err.extend("Cannot delete connection"))?; self.state = VcxStateType::VcxStateNone; Ok(error::SUCCESS.code_num) } - fn _connect_accept_invite(&mut self) -> Result { + fn _connect_accept_invite(&mut self) -> VcxResult { debug!("accepting invite for connection {}", self.source_id); let details: &InviteDetail = self.invite_detail.as_ref() - .ok_or_else(|| { - warn!("{} can not connect without invite details", self.source_id); - // TODO: Refactor Error - // TODO: Implement Correct Error - ConnectionError::GeneralConnectionError() - })?; + .ok_or(VcxError::from_msg(VcxErrorKind::GeneralConnectionError, format!("Invite details not found for: {}", self.source_id)))?; messages::accept_invite() .to(&self.pw_did)? @@ -126,16 +118,17 @@ impl Connection { .answer_status_code(&MessageStatusCode::Accepted)? .reply_to(&details.conn_req_id)? .thread(&self._build_thread(&details))? - .send_secure()?; + .send_secure() + .map_err(|err| err.extend("Cannot accept invite"))?; self.state = VcxStateType::VcxStateAccepted; + Ok(error::SUCCESS.code_num) } fn _build_thread(&self, invite_detail: &InviteDetail) -> Thread { let mut received_orders = HashMap::new(); received_orders.insert(invite_detail.sender_detail.did.clone(), 0); - Thread { thid: invite_detail.thread_id.clone(), pthid: None, @@ -144,7 +137,7 @@ impl Connection { } } - fn connect(&mut self, options: &ConnectionOptions) -> Result { + fn connect(&mut self, options: &ConnectionOptions) -> VcxResult { trace!("Connection::connect >>> options: {:?}", options); match self.state { VcxStateType::VcxStateInitialized @@ -154,7 +147,7 @@ impl Connection { warn!("connection {} in state {} not ready to connect", self.source_id, self.state as u32); // TODO: Refactor Error // TODO: Implement Correct Error - Err(ConnectionError::GeneralConnectionError()) + Err(VcxError::from_msg(VcxErrorKind::GeneralConnectionError, format!("Connection {} in state {} not ready to connect", self.source_id, self.state as u32))) } } } @@ -201,35 +194,29 @@ impl Connection { fn get_source_id(&self) -> &String { &self.source_id } fn ready_to_connect(&self) -> bool { - if self.state == VcxStateType::VcxStateNone || self.state == VcxStateType::VcxStateAccepted { - false - } else { - true - } + self.state != VcxStateType::VcxStateNone && self.state != VcxStateType::VcxStateAccepted } - fn from_str(s: &str) -> Result { - let s: Value = serde_json::from_str(&s) - .or(Err(ConnectionError::InvalidJson()))?; - let connection: Connection = serde_json::from_value(s["data"].clone()) - .or(Err(ConnectionError::InvalidJson()))?; - Ok(connection) + fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize Connection")) } - fn to_string(&self) -> String { - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json!(self), - }).to_string() + fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize Connection")) } - fn create_agent_pairwise(&mut self) -> Result { + fn create_agent_pairwise(&mut self) -> VcxResult { debug!("creating pairwise keys on agent for connection {}", self.source_id); let (for_did, for_verkey) = messages::create_keys() .for_did(&self.pw_did)? .for_verkey(&self.pw_verkey)? - .send_secure()?; + .send_secure() + .map_err(|err| err.extend("Cannot create pairwise keys"))?; debug!("create key for connection: {} with did {:?}, vk: {:?}", self.source_id, for_did, for_verkey); self.set_agent_did(&for_did); @@ -238,20 +225,21 @@ impl Connection { Ok(error::SUCCESS.code_num) } - fn update_agent_profile(&mut self, options: &ConnectionOptions) -> Result { + fn update_agent_profile(&mut self, options: &ConnectionOptions) -> VcxResult { debug!("updating agent config for connection {}", self.source_id); if let Some(true) = options.use_public_did { - self.public_did = Some(settings::get_config_value(settings::CONFIG_INSTITUTION_DID).map_err(|e| ConnectionError::CommonError(e))?); + self.public_did = Some(settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?); }; if let Ok(name) = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME) { messages::update_data() .to(&self.pw_did)? .name(&name)? - .logo_url(&settings::get_config_value(settings::CONFIG_INSTITUTION_LOGO_URL).map_err(|e| ConnectionError::CommonError(e))?)? + .logo_url(&settings::get_config_value(settings::CONFIG_INSTITUTION_LOGO_URL)?)? .use_public_did(&self.public_did)? - .send_secure()?; + .send_secure() + .map_err(|err| err.extend("Cannot update agent profile"))?; } Ok(error::SUCCESS.code_num) @@ -262,153 +250,138 @@ pub fn is_valid_handle(handle: u32) -> bool { CONNECTION_MAP.has_handle(handle) } -pub fn set_agent_did(handle: u32, did: &str) -> Result<(), ConnectionError> { +pub fn set_agent_did(handle: u32, did: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_agent_did(did); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_agent_did(did)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_agent_did(handle: u32) -> Result { +pub fn get_agent_did(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_agent_did().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_pw_did(handle: u32) -> Result { +pub fn get_pw_did(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_pw_did().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_pw_did(handle: u32, did: &str) -> Result<(), ConnectionError> { +pub fn set_pw_did(handle: u32, did: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_pw_did(did); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_pw_did(did)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_their_pw_did(handle: u32) -> Result { +pub fn get_their_pw_did(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { - Ok(cxn.get_their_pw_did().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.get_their_pw_did().to_string()) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_their_pw_did(handle: u32, did: &str) -> Result<(), ConnectionError> { +pub fn set_their_pw_did(handle: u32, did: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_their_pw_did(did); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_their_pw_did(did)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_their_public_did(handle: u32, did: &str) -> Result<(), ConnectionError> { +pub fn set_their_public_did(handle: u32, did: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_their_public_did(did); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_their_public_did(did)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_their_public_did(handle: u32) -> Result, ConnectionError> { +pub fn get_their_public_did(handle: u32) -> VcxResult> { CONNECTION_MAP.get(handle, |cxn| { - Ok(cxn.get_their_public_did().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.get_their_public_did()) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_their_pw_verkey(handle: u32) -> Result { +pub fn get_their_pw_verkey(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { - Ok(cxn.get_their_pw_verkey().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.get_their_pw_verkey().to_string()) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_their_pw_verkey(handle: u32, did: &str) -> Result<(), ConnectionError> { +pub fn set_their_pw_verkey(handle: u32, did: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_their_pw_verkey(did); - Ok(()) - }).map_err(|e| { - ConnectionError::InvalidHandle() - }) + Ok(cxn.set_their_pw_verkey(did)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_uuid(handle: u32) -> Result { +pub fn get_uuid(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { - Ok(cxn.get_uuid().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.get_uuid().to_string()) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_uuid(handle: u32, uuid: &str) -> Result<(), ConnectionError> { +pub fn set_uuid(handle: u32, uuid: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_uuid(uuid); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_uuid(uuid)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } // TODO: Add NO_ENDPOINT error to connection error -pub fn get_endpoint(handle: u32) -> Result { +pub fn get_endpoint(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_endpoint().clone()) - }).or(Err(error::NO_ENDPOINT.code_num)) + }).or(Err(VcxError::from(VcxErrorKind::NoEndpoint))) } -pub fn set_endpoint(handle: u32, endpoint: &str) -> Result<(), ConnectionError> { +pub fn set_endpoint(handle: u32, endpoint: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_endpoint(endpoint); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_endpoint(endpoint)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_agent_verkey(handle: u32) -> Result { +pub fn get_agent_verkey(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_agent_verkey().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_agent_verkey(handle: u32, verkey: &str) -> Result<(), ConnectionError> { +pub fn set_agent_verkey(handle: u32, verkey: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_agent_verkey(verkey); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_agent_verkey(verkey)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_pw_verkey(handle: u32) -> Result { +pub fn get_pw_verkey(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_pw_verkey().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_pw_verkey(handle: u32, verkey: &str) -> Result<(), ConnectionError> { +pub fn set_pw_verkey(handle: u32, verkey: &str) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_pw_verkey(verkey); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_pw_verkey(verkey)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } pub fn get_state(handle: u32) -> u32 { - match CONNECTION_MAP.get(handle, |cxn| { + CONNECTION_MAP.get(handle, |cxn| { debug!("get state for connection {}", cxn.get_source_id()); - Ok(cxn.get_state().clone()) - }) { - Ok(s) => s, - Err(_) => 0, - } + }).unwrap_or(0) } -pub fn set_state(handle: u32, state: VcxStateType) -> Result<(), ConnectionError> { +pub fn set_state(handle: u32, state: VcxStateType) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { - cxn.set_state(state); - Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + Ok(cxn.set_state(state)) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn get_source_id(handle: u32) -> Result { +pub fn get_source_id(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_source_id().clone()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn create_connection(source_id: &str) -> Result { +pub fn create_connection(source_id: &str) -> VcxResult { trace!("create_connection >>> source_id: {}", source_id); - let (pw_did, pw_verkey) = create_and_store_my_did(None).map_err(|ec| ConnectionError::CommonError(ec))?; + + let (pw_did, pw_verkey) = create_and_store_my_did(None)?; debug!("did: {} verkey: {}, source id: {}", pw_did, pw_verkey, source_id); @@ -428,24 +401,24 @@ pub fn create_connection(source_id: &str) -> Result { public_did: None, their_public_did: None, }; - let new_handle = CONNECTION_MAP.add(c).map_err(|key| ConnectionError::CreateError(key))?; - Ok(new_handle) + CONNECTION_MAP.add(c) + .or(Err(VcxError::from(VcxErrorKind::CreateConnection))) } -pub fn create_connection_with_invite(source_id: &str, details: &str) -> Result { +pub fn create_connection_with_invite(source_id: &str, details: &str) -> VcxResult { debug!("create connection {} with invite {}", source_id, details); let details: Value = serde_json::from_str(&details) - .or(Err(ConnectionError::CommonError(error::INVALID_JSON.code_num)))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize invite details: {}", err)))?; let invite_details: InviteDetail = match serde_json::from_value(details.clone()) { Ok(x) => x, Err(x) => { // Try converting to abbreviated - let details = unabbrv_event_detail(details).or(Err(ConnectionError::CommonError(error::INVALID_JSON.code_num)))?; - let invite_details = serde_json::from_value(details).or(Err(ConnectionError::CommonError(error::INVALID_JSON.code_num)))?; - invite_details + let details = unabbrv_event_detail(details)?; + serde_json::from_value(details) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize invite details: {}", err)))? } }; @@ -463,40 +436,41 @@ pub fn create_connection_with_invite(source_id: &str, details: &str) -> Result Result { +pub fn parse_acceptance_details(handle: u32, message: &Message) -> VcxResult { debug!("connection {} parsing acceptance details for message {:?}", get_source_id(handle).unwrap_or_default(), message); let my_vk = settings::get_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY)?; let payload = message.payload .as_ref() - .ok_or(ConnectionError::CommonError(error::INVALID_MSGPACK.code_num))?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidMessagePack, "Payload not found"))?; match settings::ProtocolTypes::from(settings::get_protocol_type()) { settings::ProtocolTypes::V1 => { - let payload = messages::to_u8(&payload); - // TODO: check returned verkey - let (_, payload) = crypto::parse_msg(&my_vk, &payload).map_err(|e| { ConnectionError::CommonError(e) })?; + let (_, payload) = crypto::parse_msg(&my_vk, &messages::to_u8(&payload)) + .map_err(|err| err.map(VcxErrorKind::InvalidMessagePack, "Cannot decrypt connection payload"))?; let response: ConnectionPayload = rmp_serde::from_slice(&payload[..]) - .map_err(|err| { - error!("Could not parse outer msg: {}", err); - ConnectionError::CommonError(error::INVALID_MSGPACK.code_num) - })?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Cannot parse connection payload: {}", err)))?; let payload = messages::to_u8(&response.msg); - // TODO: Refactor Error - messages::invite::parse_invitation_acceptance_details(payload).map_err(|e| { ConnectionError::CommonError(e) }) + + let response: AcceptanceDetails = rmp_serde::from_slice(&payload[..]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Cannot deserialize AcceptanceDetails: {}", err)))?; + + Ok(response.sender_detail) } settings::ProtocolTypes::V2 => { let (payload, _) = Payloads::decrypt_payload_v2(&my_vk, &payload)?; - let response: AcceptanceDetails = serde_json::from_str(&payload).or(Err(error::INVALID_JSON.code_num))?; + let response: AcceptanceDetails = serde_json::from_str(&payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize AcceptanceDetails: {}", err)))?; + Ok(response.sender_detail) } } } -pub fn update_state(handle: u32) -> Result { +pub fn update_state(handle: u32) -> VcxResult { debug!("updating state for connection {}", get_source_id(handle).unwrap_or_default()); let state = get_state(handle); @@ -517,18 +491,15 @@ pub fn update_state(handle: u32) -> Result { .agent_did(&agent_did)? .agent_vk(&agent_vk)? .send_secure() - .map_err(|err| { - error!("could not update state for handle {}: {}", handle, err); - // TODO: Refactor Error - ConnectionError::CommonError(error::POST_MSG_FAILURE.code_num) - })?; + .map_err(|err| err.map(VcxErrorKind::PostMessageFailed, format!("Could not update state for handle {}", handle)))?; debug!("connection {} update state response: {:?}", get_source_id(handle).unwrap_or_default(), response); if get_state(handle) == VcxStateType::VcxStateOfferSent as u32 || get_state(handle) == VcxStateType::VcxStateInitialized as u32 { - for i in response { - if i.status_code == MessageStatusCode::Accepted && i.msg_type == RemoteMessageType::ConnReqAnswer { - // TODO: Refactor Error - let details = parse_acceptance_details(handle, &i)?; + for message in response { + if message.status_code == MessageStatusCode::Accepted && message.msg_type == RemoteMessageType::ConnReqAnswer { + let details = parse_acceptance_details(handle, &message) + .map_err(|err| err.extend("Cannot parse acceptance details"))?; + set_their_pw_did(handle, &details.did).ok(); set_their_pw_verkey(handle, &details.verkey).ok(); set_state(handle, VcxStateType::VcxStateAccepted).ok(); @@ -539,102 +510,88 @@ pub fn update_state(handle: u32) -> Result { Ok(error::SUCCESS.code_num) } -pub fn delete_connection(handle: u32) -> Result { +pub fn delete_connection(handle: u32) -> VcxResult { CONNECTION_MAP.get_mut(handle, |t| { debug!("delete connection: {}", t.get_source_id()); - match t.delete_connection() { - Ok(x) => Ok(x), - Err(e) => { - return Err(e.to_error_code()); - } - } + t.delete_connection() }) - .or(Err(ConnectionError::CannotDeleteConnection())) + .or(Err(VcxError::from(VcxErrorKind::DeleteConnection))) .and(release(handle)) .and_then(|_| Ok(error::SUCCESS.code_num)) } -pub fn connect(handle: u32, options: Option) -> Result { +pub fn connect(handle: u32, options: Option) -> VcxResult { let options_obj: ConnectionOptions = match options.as_ref().map(|opt| opt.trim()) { None => ConnectionOptions::default(), Some(opt) if opt.is_empty() => ConnectionOptions::default(), Some(opt) => { serde_json::from_str(&opt) - .or(Err(ConnectionError::CommonError(error::INVALID_OPTION.code_num)))? + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidOption, format!("Cannot deserialize ConnectionOptions: {}", err)))? } }; CONNECTION_MAP.get_mut(handle, |t| { debug!("establish connection {}", t.get_source_id()); - t.create_agent_pairwise().map_err(|ec| ec.to_error_code())?; - t.update_agent_profile(&options_obj).map_err(|ec| ec.to_error_code())?; - t.connect(&options_obj).map_err(|ec| ec.to_error_code()) - }).map_err(|ec| ConnectionError::CommonError(ec)) + t.create_agent_pairwise()?; + t.update_agent_profile(&options_obj)?; + t.connect(&options_obj) + }) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { CONNECTION_MAP.get(handle, |t| { - // TODO: Make this an error.to_error_code and back again? - Ok(Connection::to_string(&t)) - }).or(Err(error::INVALID_CONNECTION_HANDLE.code_num)) + Connection::to_string(&t) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn from_string(connection_data: &str) -> Result { +pub fn from_string(connection_data: &str) -> VcxResult { let derived_connection: Connection = Connection::from_str(connection_data)?; - - let new_handle = CONNECTION_MAP.add(derived_connection).map_err(|ec| ConnectionError::CommonError(ec))?; - debug!("inserting handle {} source_id {} into connection table", new_handle, get_source_id(new_handle).unwrap_or_default()); - - Ok(new_handle) + let handle = CONNECTION_MAP.add(derived_connection)?; + debug!("inserting handle {} source_id {} into connection table", handle, get_source_id(handle).unwrap_or_default()); + Ok(handle) } -pub fn release(handle: u32) -> Result<(), ConnectionError> { - match CONNECTION_MAP.release(handle) { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::InvalidHandle()) - } +pub fn release(handle: u32) -> VcxResult<()> { + CONNECTION_MAP.release(handle) + .or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } pub fn release_all() { - match CONNECTION_MAP.drain() { - Ok(_) => (), - // TODO: This needs to be better - Err(_) => (), - }; + CONNECTION_MAP.drain().ok(); } -pub fn get_invite_details(handle: u32, abbreviated: bool) -> Result { +pub fn get_invite_details(handle: u32, abbreviated: bool) -> VcxResult { debug!("get invite details for connection {}", get_source_id(handle).unwrap_or_default()); CONNECTION_MAP.get(handle, |t| { match abbreviated { false => { - Ok(serde_json::to_string(&t.invite_detail) - .or(Err(ConnectionError::InviteDetailError()))) + serde_json::to_string(&t.invite_detail) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidInviteDetail, format!("Cannot serialize InviteDetail: {}", err))) } true => { - let details = serde_json::to_value(&t.invite_detail).or(Err(ConnectionError::InviteDetailError().to_error_code()))?; + let details = serde_json::to_value(&t.invite_detail) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidInviteDetail, format!("Cannot serialize InviteDetail: {}", err)))?; let abbr = abbrv_event_detail(details)?; - Ok(serde_json::to_string(&abbr).or(Err(ConnectionError::InviteDetailError()))) + serde_json::to_string(&abbr) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidInviteDetail, format!("Cannot serialize abbreviated InviteDetail: {}", err))) } } - }).or(Err(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num)))? + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } -pub fn set_invite_details(handle: u32, invite_detail: &InviteDetail) -> Result<(), ConnectionError> { +pub fn set_invite_details(handle: u32, invite_detail: &InviteDetail) -> VcxResult<()> { CONNECTION_MAP.get_mut(handle, |cxn| { cxn.set_invite_detail(invite_detail.clone()); - // TODO: Verify that this is ok to do...seems not rusty. Ok(()) - }).or(Err(ConnectionError::InvalidHandle())) + }).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle))) } //********** // Code to convert InviteDetails to Abbreviated String //********** - impl KeyMatch for (String, Option) { fn matches(&self, key: &String, context: &Vec) -> bool { if key.eq(&self.0) { @@ -700,12 +657,13 @@ lazy_static! { }; } -fn abbrv_event_detail(val: Value) -> Result { +fn abbrv_event_detail(val: Value) -> VcxResult { mapped_key_rewrite(val, &ABBREVIATIONS) } -fn unabbrv_event_detail(val: Value) -> Result { +fn unabbrv_event_detail(val: Value) -> VcxResult { mapped_key_rewrite(val, &UNABBREVIATIONS) + .map_err(|err| err.extend("Cannot unabbreviate event detail")) } @@ -751,8 +709,7 @@ pub mod tests { fn test_build_connection_failures() { init!("true"); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); - assert_eq!(create_connection("This Should Fail").err(), - Some(ConnectionError::CommonError(error::INVALID_WALLET_HANDLE.code_num))); + assert_eq!(create_connection("This Should Fail").unwrap_err().kind(), VcxErrorKind::InvalidWalletHandle); assert!(create_connection_with_invite("This Should Fail", "BadDetailsFoobar").is_err()); } @@ -761,7 +718,7 @@ pub mod tests { init!("indy"); let handle = create_connection("invalid").unwrap(); let rc = connect(handle, None); - assert_eq!(rc.unwrap_err(), ConnectionError::CommonError(error::POST_MSG_FAILURE.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::PostMessageFailed); } #[test] @@ -794,8 +751,7 @@ pub mod tests { #[test] fn test_connection_release_fails() { let rc = release(1); - assert_eq!(rc.err(), - Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); } #[test] @@ -840,8 +796,7 @@ pub mod tests { update_state(handle).unwrap(); let details = get_invite_details(handle, true).unwrap(); assert!(details.contains("\"dp\":")); - assert_eq!(get_invite_details(12345, true).err(), - Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(get_invite_details(12345, true).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); } #[test] @@ -882,7 +837,7 @@ pub mod tests { fn test_bad_wallet_connection_fails() { init!("true"); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); - assert_eq!(create_connection("test_bad_wallet_connection_fails").unwrap_err().to_error_code(), error::INVALID_WALLET_HANDLE.code_num); + assert_eq!(create_connection("test_bad_wallet_connection_fails").unwrap_err().kind(), VcxErrorKind::InvalidWalletHandle); } #[test] @@ -940,7 +895,7 @@ pub mod tests { Ok(_) => assert_eq!(0, 1), // we should not receive this // TODO: Refactor Error // TODO: Fix this test to be a correct Error Type - Err(e) => assert_eq!(e, ConnectionError::CommonError(1019)), + Err(e) => assert_eq!(e.kind(), VcxErrorKind::InvalidMessagePack), } } @@ -1016,11 +971,11 @@ pub mod tests { let h4 = create_connection("rel4").unwrap(); let h5 = create_connection("rel5").unwrap(); release_all(); - assert_eq!(release(h1).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h2).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h3).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h4).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h5).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h1).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + assert_eq!(release(h2).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + assert_eq!(release(h3).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + assert_eq!(release(h4).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + assert_eq!(release(h5).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); } #[test] @@ -1046,13 +1001,12 @@ pub mod tests { let bad_details = r#"{"id":"mtfjmda","s":{"d":"abc"},"l":"abc","n":"Evernym","v":"avc"},"sa":{"d":"abc","e":"abc","v":"abc"},"sc":"MS-101","sm":"message created","t":"there"}"#; match create_connection_with_invite("alice", &bad_details) { Ok(_) => panic!("should have failed"), - Err(x) => assert_eq!(x, ConnectionError::CommonError(error::INVALID_JSON.code_num)), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::InvalidJson), }; } #[test] fn test_connect_with_invalid_details() { - use error::connection::ConnectionError; init!("true"); let test_name = "test_connect_with_invalid_details"; @@ -1075,28 +1029,39 @@ pub mod tests { let handle = CONNECTION_MAP.add(c).unwrap(); - assert_eq!(connect(handle, Some("{}".to_string())).err(), Some(ConnectionError::CommonError(error::CONNECTION_ERROR.code_num))); + assert_eq!(connect(handle, Some("{}".to_string())).unwrap_err().kind(), VcxErrorKind::GeneralConnectionError); + ; // from_string throws a ConnectionError - assert_eq!(from_string("").err(), Some(ConnectionError::CommonError(1016))); + assert_eq!(from_string("").unwrap_err().kind(), VcxErrorKind::InvalidJson); + ; // release throws a connection Error - assert_eq!(release(1234).err(), - Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(1234).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; } #[test] fn test_void_functions_actually_have_results() { - assert_eq!(set_their_pw_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_state(1, VcxStateType::VcxStateNone).err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_pw_did(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_their_pw_did(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_uuid(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_endpoint(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_agent_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_their_pw_verkey(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_state(1, VcxStateType::VcxStateNone).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_pw_did(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_their_pw_did(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_uuid(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_endpoint(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_agent_verkey(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; let details: InviteDetail = serde_json::from_str(INVITE_DETAIL_STRING).unwrap(); - assert_eq!(set_invite_details(1, &details).err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_pw_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_invite_details(1, &details).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; + assert_eq!(set_pw_verkey(1, "blah").unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle); + ; } #[test] @@ -1104,6 +1069,6 @@ pub mod tests { init!("true"); let details = r#"{"id":"njjmmdg","s":{"d":"JZho9BzVAEk8jJ1hwrrDiZ","dp":{"d":"JDF8UHPBTXigvtJWeeMJzx","k":"AP5SzUaHHhF5aLmyKHB3eTqUaREGKyVttwo5T4uwEkM4","s":"JHSvITBMZiTEhpK61EDIWjQOLnJ8iGQ3FT1nfyxNNlxSngzp1eCRKnGC/RqEWgtot9M5rmTC8QkZTN05GGavBg=="},"l":"https://robohash.org/123","n":"Evernym","v":"AaEDsDychoytJyzk4SuzHMeQJGCtQhQHDitaic6gtiM1"},"sa":{"d":"YRuVCckY6vfZfX9kcQZe3u","e":"52.38.32.107:80/agency/msg","v":"J8Yct6FwmarXjrE2khZesUXRVVSVczSoa9sFaGe6AD2v"},"sc":"MS-101","sm":"message created","t":"there"}"#; let handle = create_connection_with_invite("alice", &details).unwrap(); - assert_eq!(release(handle), Ok(())); + assert_eq!(release(handle).unwrap(), ()); } } diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index 07ee4c6f9a..1d2c6b1b49 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -1,32 +1,22 @@ -extern crate rand; -extern crate serde_json; -extern crate libc; -extern crate serde; -extern crate rmp_serde; +use serde_json; +use serde_json::Value; use object_cache::ObjectCache; use api::VcxStateType; -use utils::error; use issuer_credential::{CredentialOffer, CredentialMessage, PaymentInfo}; - use credential_request::CredentialRequest; - use messages; -use messages::{GeneralMessage, RemoteMessageType}; +use messages::{GeneralMessage, RemoteMessageType, ObjectWithVersion}; use messages::payload::{Payloads, PayloadKinds, Thread}; - +use messages::get_message; +use connection; +use settings; use utils::libindy::anoncreds::{libindy_prover_create_credential_req, libindy_prover_store_credential}; use utils::libindy::anoncreds; use utils::libindy::payments::{pay_a_payee, PaymentTxn}; - -use connection; - -use settings; +use utils::error; use utils::constants::DEFAULT_SERIALIZE_VERSION; - -use error::{ToErrorCode, credential::CredentialError}; -use serde_json::Value; - +use error::prelude::*; lazy_static! { static ref HANDLE_MAP: ObjectCache = Default::default(); @@ -57,7 +47,7 @@ impl Default for Credential { } } -#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Credential { source_id: String, state: VcxStateType, @@ -80,15 +70,15 @@ pub struct Credential { } impl Credential { - pub fn build_request(&self, my_did: &str, their_did: &str) -> Result { + pub fn build_request(&self, my_did: &str, their_did: &str) -> VcxResult { trace!("Credential::build_request >>> my_did: {}, their_did: {}", my_did, their_did); if self.state != VcxStateType::VcxStateRequestReceived { - return Err(CredentialError::NotReady()); + return Err(VcxError::from_msg(VcxErrorKind::NotReady, format!("credential {} has invalid state {} for sending credential request", self.source_id, self.state as u32))); } - let prover_did = self.my_did.as_ref().ok_or(CredentialError::CommonError(error::INVALID_DID.code_num))?; - let credential_offer = self.credential_offer.as_ref().ok_or(CredentialError::InvalidCredentialJson())?; + let prover_did = self.my_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidDid))?; + let credential_offer = self.credential_offer.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredential))?; let (cred_def_id, cred_def_json) = anoncreds::get_cred_def_json(&credential_offer.cred_def_id)?; @@ -99,7 +89,8 @@ impl Credential { let (req, req_meta) = libindy_prover_create_credential_req(&prover_did, &credential_offer.libindy_offer, - &cred_def_json)?; + &cred_def_json) + .map_err(|err| err.extend("Cannot create credential request"))?; Ok(CredentialRequest { libindy_cred_req: req, @@ -114,16 +105,16 @@ impl Credential { }) } - fn send_request(&mut self, connection_handle: u32) -> Result { + fn send_request(&mut self, connection_handle: u32) -> VcxResult { trace!("Credential::send_request >>> connection_handle: {}", connection_handle); debug!("sending credential request {} via connection: {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); - self.my_did = Some(connection::get_pw_did(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); - self.my_vk = Some(connection::get_pw_verkey(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); - self.agent_did = Some(connection::get_agent_did(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); - self.agent_vk = Some(connection::get_agent_verkey(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); - self.their_did = Some(connection::get_their_pw_did(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); - self.their_vk = Some(connection::get_their_pw_verkey(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); + self.my_did = Some(connection::get_pw_did(connection_handle)?); + self.my_vk = Some(connection::get_pw_verkey(connection_handle)?); + self.agent_did = Some(connection::get_agent_did(connection_handle)?); + self.agent_vk = Some(connection::get_agent_verkey(connection_handle)?); + self.their_did = Some(connection::get_their_pw_did(connection_handle)?); + self.their_vk = Some(connection::get_their_pw_verkey(connection_handle)?); debug!("verifier_did: {:?} -- verifier_vk: {:?} -- agent_did: {:?} -- agent_vk: {:?} -- remote_vk: {:?}", self.my_did, @@ -132,21 +123,22 @@ impl Credential { self.their_vk, self.my_vk); - let local_their_did = self.their_did.as_ref().ok_or(CredentialError::InvalidHandle())?; - let local_their_vk = self.their_vk.as_ref().ok_or(CredentialError::InvalidHandle())?; - let local_agent_did = self.agent_did.as_ref().ok_or(CredentialError::InvalidHandle())?; - let local_agent_vk = self.agent_vk.as_ref().ok_or(CredentialError::InvalidHandle())?; - let local_my_did = self.my_did.as_ref().ok_or(CredentialError::InvalidHandle())?; - let local_my_vk = self.my_vk.as_ref().ok_or(CredentialError::InvalidHandle())?; + let local_their_did = self.their_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let local_their_vk = self.their_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let local_agent_did = self.agent_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let local_agent_vk = self.agent_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let local_my_did = self.my_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let local_my_vk = self.my_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; // if test mode, just get this. let cred_req: CredentialRequest = self.build_request(local_my_did, local_their_did)?; - let cred_req_json = serde_json::to_string(&cred_req).or(Err(CredentialError::InvalidCredentialJson()))?; + let cred_req_json = serde_json::to_string(&cred_req) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidCredential, format!("Cannot serialize CredentialRequest: {}", err)))?; self.credential_request = Some(cred_req); let offer_msg_id = self.credential_offer.as_ref().and_then(|offer| offer.msg_ref_id.clone()) - .ok_or(CredentialError::CommonError(error::CREATE_CREDENTIAL_REQUEST_ERROR.code_num))?; + .ok_or(VcxError::from(VcxErrorKind::CreateCredentialRequest))?; if self.payment_info.is_some() { let (payment_txn, _) = self.submit_payment()?; @@ -163,10 +155,7 @@ impl Credential { .edge_agent_payload(&local_my_vk, &local_their_vk, &cred_req_json, PayloadKinds::CredReq, self.thread.clone())? .ref_msg_id(&offer_msg_id)? .send_secure() - .map_err(|err| { - warn!("{} could not send proof: {}", self.source_id, err); - err - })?; + .map_err(|err| err.extend(format!("{} could not send proof", self.source_id)))?; self.msg_uid = Some(response.get_msg_uid()?); self.state = VcxStateType::VcxStateOfferSent; @@ -174,16 +163,14 @@ impl Credential { return Ok(error::SUCCESS.code_num); } - fn _check_msg(&mut self) -> Result<(), u32> { - let e_code: u32 = error::INVALID_CONNECTION_HANDLE.code_num; - - let agent_did = self.agent_did.as_ref().ok_or(e_code)?; - let agent_vk = self.agent_vk.as_ref().ok_or(e_code)?; - let my_did = self.my_did.as_ref().ok_or(e_code)?; - let my_vk = self.my_vk.as_ref().ok_or(e_code)?; - let msg_uid = self.msg_uid.as_ref().ok_or(e_code)?; + fn _check_msg(&mut self) -> VcxResult<()> { + let agent_did = self.agent_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let agent_vk = self.agent_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let my_did = self.my_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let my_vk = self.my_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; + let msg_uid = self.msg_uid.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidCredentialHandle))?; - let (_, payload) = messages::get_message::get_ref_msg(msg_uid, my_did, my_vk, agent_did, agent_vk)?; + let (_, payload) = get_message::get_ref_msg(msg_uid, my_did, my_vk, agent_did, agent_vk)?; let (credential, thread) = Payloads::decrypt(&my_vk, &payload)?; @@ -193,12 +180,13 @@ impl Credential { } let credential_msg: CredentialMessage = serde_json::from_str(&credential) - .or(Err(error::INVALID_CREDENTIAL_JSON.code_num))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidCredential, format!("Cannot deserialize CredentialMessage: {}", err)))?; let cred_req: &CredentialRequest = self.credential_request.as_ref() - .ok_or(CredentialError::InvalidCredentialJson().to_error_code())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidCredential, "Cannot find CredentialRequest"))?; - let (_, cred_def_json) = anoncreds::get_cred_def_json(&cred_req.cred_def_id)?; + let (_, cred_def_json) = anoncreds::get_cred_def_json(&cred_req.cred_def_id) + .map_err(|err| err.extend("Cannot get credential definition"))?; self.credential = Some(credential); self.cred_id = Some(libindy_prover_store_credential(None, @@ -207,7 +195,7 @@ impl Credential { &cred_def_json, match credential_msg.rev_reg_def_json.len() { 0 => None, - _ => Some(credential_msg.rev_reg_def_json), + _ => Some(&credential_msg.rev_reg_def_json), })?); self.state = VcxStateType::VcxStateAccepted; @@ -233,149 +221,133 @@ impl Credential { fn get_state(&self) -> u32 { trace!("Credential::get_state >>>"); - let state = self.state as u32; - state + self.state as u32 } - fn get_credential(&self) -> Result { + fn get_credential(&self) -> VcxResult { trace!("Credential::get_credential >>>"); if self.state != VcxStateType::VcxStateAccepted { - return Err(CredentialError::InvalidState()); + return Err(VcxError::from(VcxErrorKind::InvalidState)); } - let credential = self.credential.as_ref().ok_or(CredentialError::InvalidState())?; + let credential = self.credential.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidState))?; Ok(self.to_cred_string(&credential)) } - fn get_credential_offer(&self) -> Result { + fn get_credential_offer(&self) -> VcxResult { trace!("Credential::get_credential_offer >>>"); if self.state != VcxStateType::VcxStateRequestReceived { - return Err(CredentialError::InvalidState()); + return Err(VcxError::from(VcxErrorKind::InvalidState)); } - let credential_offer = self.credential_offer.as_ref().ok_or(CredentialError::InvalidState())?; - let credential_offer_json = serde_json::to_string(credential_offer).or(Err(CredentialError::InvalidCredentialJson()))?; + let credential_offer = self.credential_offer.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidState))?; + let credential_offer_json = serde_json::to_string(credential_offer) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidCredential, format!("Cannot deserialize CredentilOffer: {}", err)))?; Ok(self.to_cred_offer_string(&credential_offer_json)) } fn get_credential_id(&self) -> String { - match self.cred_id.as_ref() { - Some(cid) => cid.to_string(), - None => "".to_string(), - } + self.cred_id.as_ref().map(String::as_str).unwrap_or("").to_string() } - fn set_payment_info(&self, json: &mut serde_json::Map) { + fn set_payment_info(&self, json: &mut serde_json::Map) { if let Some(ref payment_info) = self.payment_info { - json.insert("price".to_string(), serde_json::Value::String(payment_info.price.to_string())); - json.insert("payment_address".to_string(), serde_json::Value::String(payment_info.payment_addr.to_string())); + json.insert("price".to_string(), Value::String(payment_info.price.to_string())); + json.insert("payment_address".to_string(), Value::String(payment_info.payment_addr.to_string())); }; } fn to_cred_string(&self, cred: &str) -> String { - let cred = { - let mut json = serde_json::Map::new(); - json.insert("credential_id".to_string(), serde_json::Value::String(self.get_credential_id())); - json.insert("credential".to_string(), serde_json::Value::String(cred.to_string())); - self.set_payment_info(&mut json); - serde_json::Value::from(json).to_string() - }; - cred + let mut json = serde_json::Map::new(); + json.insert("credential_id".to_string(), Value::String(self.get_credential_id())); + json.insert("credential".to_string(), Value::String(cred.to_string())); + self.set_payment_info(&mut json); + serde_json::Value::from(json).to_string() } fn to_cred_offer_string(&self, cred_offer: &str) -> String { - let cred_offer = { - let mut json = serde_json::Map::new(); - json.insert("credential_offer".to_string(), serde_json::Value::String(cred_offer.to_string())); - self.set_payment_info(&mut json); - serde_json::Value::from(json).to_string() - }; - cred_offer + let mut json = serde_json::Map::new(); + json.insert("credential_offer".to_string(), Value::String(cred_offer.to_string())); + self.set_payment_info(&mut json); + serde_json::Value::from(json).to_string() } fn set_source_id(&mut self, id: &str) { self.source_id = id.to_string(); } fn get_source_id(&self) -> &String { &self.source_id } - fn get_payment_txn(&self) -> Result { + fn get_payment_txn(&self) -> VcxResult { trace!("Credential::get_payment_txn >>>"); match (&self.payment_txn, &self.payment_info) { (Some(ref payment_txn), Some(_)) => Ok(payment_txn.clone()), - _ => Err(error::NO_PAYMENT_INFORMATION.code_num) + _ => Err(VcxError::from(VcxErrorKind::NoPaymentInformation)) } } - fn set_credential_offer(&mut self, offer: CredentialOffer) { - self.credential_offer = Some(offer); - } - fn is_payment_required(&self) -> bool { self.payment_info.is_some() } - fn submit_payment(&self) -> Result<(PaymentTxn, String), CredentialError> { + fn submit_payment(&self) -> VcxResult<(PaymentTxn, String)> { debug!("{} submitting payment for premium credential", self.source_id); match &self.payment_info { &Some(ref pi) => { - let address = &pi.get_address()?; - let price = pi.get_price()?; + let address = &pi.get_address(); + let price = pi.get_price(); let (payment_txn, receipt) = pay_a_payee(price, address)?; Ok((payment_txn, receipt)) } - &None => Err(CredentialError::NoPaymentInformation()), + &None => Err(VcxError::from(VcxErrorKind::NoPaymentInformation)), } } - fn get_payment_info(&self) -> Result, CredentialError> { + fn get_payment_info(&self) -> VcxResult> { trace!("Credential::get_payment_info >>>"); Ok(self.payment_info.clone()) } - fn to_string(&self) -> String { - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json!(self), - }).to_string() + fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize Credential")) } - fn from_str(s: &str) -> Result { - let s: Value = serde_json::from_str(&s) - .or(Err(CredentialError::InvalidCredentialJson()))?; - let obj: Credential = serde_json::from_value(s["data"].clone()) - .or(Err(CredentialError::InvalidCredentialJson()))?; - Ok(obj) + fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize Credential")) } } //******************************************** // HANDLE FUNCTIONS //******************************************** -fn handle_err(code_num: u32) -> CredentialError { - if code_num == error::INVALID_OBJ_HANDLE.code_num { - CredentialError::InvalidHandle() +fn handle_err(err: VcxError) -> VcxError { + if err.kind() == VcxErrorKind::InvalidHandle { + VcxError::from(VcxErrorKind::InvalidCredentialHandle) } else { - CredentialError::CommonError(code_num) + err } } -pub fn credential_create_with_offer(source_id: &str, offer: &str) -> Result { +pub fn credential_create_with_offer(source_id: &str, offer: &str) -> VcxResult { trace!("credential_create_with_offer >>> source_id: {}, offer: {}", source_id, offer); let mut new_credential = _credential_create(source_id); let (offer, payment_info) = parse_json_offer(offer)?; - new_credential.set_credential_offer(offer); - new_credential.payment_info = payment_info; + new_credential.credential_offer = Some(offer); + new_credential.payment_info = payment_info; new_credential.state = VcxStateType::VcxStateRequestReceived; debug!("inserting credential {} into handle map", source_id); - Ok(HANDLE_MAP.add(new_credential).map_err(|ec| CredentialError::CommonError(ec))?) + HANDLE_MAP.add(new_credential) } fn _credential_create(source_id: &str) -> Credential { @@ -387,7 +359,7 @@ fn _credential_create(source_id: &str) -> Credential { new_credential } -pub fn update_state(handle: u32) -> Result { +pub fn update_state(handle: u32) -> VcxResult { HANDLE_MAP.get_mut(handle, |obj| { debug!("updating state for credential {} with msg_id {:?}", obj.source_id, obj.msg_uid); obj.update_state(); @@ -395,127 +367,129 @@ pub fn update_state(handle: u32) -> Result { }) } -pub fn get_credential(handle: u32) -> Result { +pub fn get_credential(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { debug!("getting credential {}", obj.get_source_id()); - obj.get_credential().map_err(|e| e.to_error_code()) - }).map_err(|ec| CredentialError::CommonError(ec)) + obj.get_credential() + }) } -pub fn get_payment_txn(handle: u32) -> Result { +pub fn get_payment_txn(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { obj.get_payment_txn() - }).or(Err(CredentialError::NoPaymentInformation())) + }).or(Err(VcxError::from(VcxErrorKind::NoPaymentInformation))) } -pub fn get_credential_offer(handle: u32) -> Result { +pub fn get_credential_offer(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { debug!("getting credential offer {}", obj.source_id); - obj.get_credential_offer().map_err(|e| e.to_error_code()) - }).map_err(|ec| CredentialError::CommonError(ec)) + obj.get_credential_offer() + }) } -pub fn get_credential_id(handle: u32) -> Result { +pub fn get_credential_id(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_credential_id()) - }).map_err(|ec| CredentialError::CommonError(ec)) + }) } -pub fn get_state(handle: u32) -> Result { +pub fn get_state(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_state()) }).map_err(handle_err) } -pub fn send_credential_request(handle: u32, connection_handle: u32) -> Result { +pub fn send_credential_request(handle: u32, connection_handle: u32) -> VcxResult { HANDLE_MAP.get_mut(handle, |obj| { - obj.send_request(connection_handle).map_err(|e| e.to_error_code()) + obj.send_request(connection_handle) }).map_err(handle_err) } -pub fn get_credential_offer_msg(connection_handle: u32, msg_id: &str) -> Result { +pub fn get_credential_offer_msg(connection_handle: u32, msg_id: &str) -> VcxResult { trace!("get_credential_offer_msg >>> connection_handle: {}, msg_id: {}", connection_handle, msg_id); - let my_did = connection::get_pw_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let agent_did = connection::get_agent_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let agent_vk = connection::get_agent_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; + let my_did = connection::get_pw_did(connection_handle)?; + let my_vk = connection::get_pw_verkey(connection_handle)?; + let agent_did = connection::get_agent_did(connection_handle)?; + let agent_vk = connection::get_agent_verkey(connection_handle)?; if settings::test_agency_mode_enabled() { ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_CREDENTIAL_OFFER_RESPONSE.to_vec()); } - let message = messages::get_message::get_connection_messages(&my_did, - &my_vk, - &agent_did, - &agent_vk, - Some(vec![msg_id.to_string()])).map_err(|ec| CredentialError::CommonError(ec))?; - - if message[0].msg_type == RemoteMessageType::CredOffer { - let payload = message.get(0).and_then(|msg| msg.payload.as_ref()) - .ok_or(CredentialError::CommonError(error::INVALID_MESSAGES.code_num))?; + let message = get_message::get_connection_messages(&my_did, + &my_vk, + &agent_did, + &agent_vk, + Some(vec![msg_id.to_string()])) + .map_err(|err| err.extend("Cannot get messages"))?; - let (offer, thread) = Payloads::decrypt(&my_vk, &payload).map_err(|ec| CredentialError::CommonError(ec))?; - - let (mut offer, payment_info) = parse_json_offer(&offer)?; + if message[0].msg_type != RemoteMessageType::CredOffer { + return Err(VcxError::from_msg(VcxErrorKind::InvalidMessages, "Invalid message type")); + } - offer.msg_ref_id = Some(message[0].uid.to_owned()); + let payload = message.get(0).and_then(|msg| msg.payload.as_ref()) + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidMessagePack, "Payload not found"))?; - if let Some(tr) = thread { - offer.thread_id = tr.thid.clone(); - } - let mut payload = Vec::new(); - payload.push(json!(offer)); - if let Some(p) = payment_info { payload.push(json!(p)); } + let payload = _set_cred_offer_ref_message(&payload, &my_vk, &message[0].uid)?; - Ok(serde_json::to_string_pretty(&payload).or(Err(CredentialError::CommonError(error::INVALID_MESSAGES.code_num)))?) - } else { - Err(CredentialError::CommonError(error::INVALID_MESSAGES.code_num)) - } + serde_json::to_string_pretty(&payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidMessages, format!("Cannot serialize credential offer: {}", err))) } -pub fn get_credential_offer_messages(connection_handle: u32) -> Result { +pub fn get_credential_offer_messages(connection_handle: u32) -> VcxResult { trace!("Credential::get_credential_offer_messages >>> connection_handle: {}", connection_handle); debug!("checking agent for credential offers from connection {}", connection::get_source_id(connection_handle).unwrap_or_default()); - let my_did = connection::get_pw_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let agent_did = connection::get_agent_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; - let agent_vk = connection::get_agent_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; + let my_did = connection::get_pw_did(connection_handle)?; + let my_vk = connection::get_pw_verkey(connection_handle)?; + let agent_did = connection::get_agent_did(connection_handle)?; + let agent_vk = connection::get_agent_verkey(connection_handle)?; if settings::test_agency_mode_enabled() { ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_CREDENTIAL_OFFER_RESPONSE.to_vec()); } - let payload = messages::get_message::get_connection_messages(&my_did, - &my_vk, - &agent_did, - &agent_vk, - None).map_err(|ec| CredentialError::CommonError(ec))?; + let payload = get_message::get_connection_messages(&my_did, + &my_vk, + &agent_did, + &agent_vk, + None) + .map_err(|err| err.extend("Cannot get messages"))?; let mut messages = Vec::new(); for msg in payload { if msg.msg_type == RemoteMessageType::CredOffer { - let payload = msg.payload.ok_or(CredentialError::CommonError(error::INVALID_MESSAGES.code_num))?; - let (offer, thread) = Payloads::decrypt(&my_vk, &payload).map_err(|ec| CredentialError::CommonError(ec))?; + let payload = msg.payload + .ok_or(VcxError::from(VcxErrorKind::InvalidMessages))?; - let (mut offer, payment_info) = parse_json_offer(&offer)?; - - offer.msg_ref_id = Some(msg.uid.to_owned()); - if let Some(tr) = thread { - offer.thread_id = tr.thid.clone(); - } - - let mut payload = Vec::new(); - payload.push(json!(offer)); - if let Some(p) = payment_info { payload.push(json!(p)); } + let payload = _set_cred_offer_ref_message(&payload, &my_vk, &msg.uid)?; messages.push(payload); } } - Ok(serde_json::to_string_pretty(&messages).or(Err(CredentialError::CommonError(error::INVALID_MESSAGES.code_num)))?) + serde_json::to_string_pretty(&messages) + .or(Err(VcxError::from(VcxErrorKind::InvalidMessages))) } -pub fn parse_json_offer(offer: &str) -> Result<(CredentialOffer, Option), CredentialError> { - let paid_offer: Value = serde_json::from_str(offer).or(Err(CredentialError::InvalidCredentialJson()))?; +fn _set_cred_offer_ref_message(payload: &Vec, my_vk: &str, msg_id: &str) -> VcxResult> { + let (offer, thread) = Payloads::decrypt(my_vk, payload)?; + + let (mut offer, payment_info) = parse_json_offer(&offer)?; + + offer.msg_ref_id = Some(msg_id.to_owned()); + if let Some(tr) = thread { + offer.thread_id = tr.thid.clone(); + } + + let mut payload = Vec::new(); + payload.push(json!(offer)); + if let Some(p) = payment_info { payload.push(json!(p)); } + + Ok(payload) +} + +pub fn parse_json_offer(offer: &str) -> VcxResult<(CredentialOffer, Option)> { + let paid_offer: Value = serde_json::from_str(offer) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize offer: {}", err)))?; let mut payment: Option = None; let mut offer: Option = None; @@ -523,50 +497,45 @@ pub fn parse_json_offer(offer: &str) -> Result<(CredentialOffer, Option Result<(), CredentialError> { +pub fn release(handle: u32) -> VcxResult<()> { HANDLE_MAP.release(handle).map_err(handle_err) } pub fn release_all() { - match HANDLE_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + HANDLE_MAP.drain().ok(); } pub fn is_valid_handle(handle: u32) -> bool { HANDLE_MAP.has_handle(handle) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { - Ok(Credential::to_string(&obj)) + Credential::to_string(&obj) }) } -pub fn get_source_id(handle: u32) -> Result { +pub fn get_source_id(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_source_id().clone()) }).map_err(handle_err) } -pub fn from_string(credential_data: &str) -> Result { - let credential: Credential = match Credential::from_str(credential_data) { - Ok(x) => x, - Err(y) => return Err(error::INVALID_JSON.code_num), - }; - +pub fn from_string(credential_data: &str) -> VcxResult { + let credential: Credential = Credential::from_str(credential_data)?; let new_handle = HANDLE_MAP.add(credential)?; debug!("inserting handle {} into proof table", new_handle); @@ -574,21 +543,21 @@ pub fn from_string(credential_data: &str) -> Result { Ok(new_handle) } -pub fn is_payment_required(handle: u32) -> Result { +pub fn is_payment_required(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.is_payment_required()) }).map_err(handle_err) } -pub fn submit_payment(handle: u32) -> Result<(PaymentTxn, String), CredentialError> { +pub fn submit_payment(handle: u32) -> VcxResult<(PaymentTxn, String)> { HANDLE_MAP.get_mut(handle, |obj| { - obj.submit_payment().map_err(|e| e.to_error_code()) + obj.submit_payment() }).map_err(handle_err) } -pub fn get_payment_information(handle: u32) -> Result, CredentialError> { +pub fn get_payment_information(handle: u32) -> VcxResult> { HANDLE_MAP.get(handle, |obj| { - obj.get_payment_info().map_err(|e| e.to_error_code()) + obj.get_payment_info() }).map_err(handle_err) } @@ -631,7 +600,7 @@ pub mod tests { #[test] fn test_credential_defaults() { let credential = Credential::default(); - assert_eq!(credential.build_request("test1", "test2").err(), Some(CredentialError::NotReady())); + assert_eq!(credential.build_request("test1", "test2").unwrap_err().kind(), VcxErrorKind::NotReady); } #[test] @@ -644,7 +613,7 @@ pub mod tests { fn test_credential_create_with_bad_offer() { match credential_create_with_offer("test_credential_create_with_bad_offer", BAD_CREDENTIAL_OFFER) { Ok(_) => panic!("should have failed with bad credential offer"), - Err(x) => assert_eq!(x.to_error_code(), error::INVALID_JSON.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::InvalidJson) }; } @@ -653,7 +622,7 @@ pub mod tests { let handle = credential_create_with_offer("test_credential_serialize_deserialize", ::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); let credential_string = to_string(handle).unwrap(); release(handle).unwrap(); - assert_eq!(release(handle).err(), Some(CredentialError::InvalidHandle())); + assert_eq!(release(handle).unwrap_err().kind(), VcxErrorKind::InvalidCredentialHandle); let handle = from_string(&credential_string).unwrap(); let cred1: Credential = Credential::from_str(&credential_string).unwrap(); assert_eq!(cred1.get_state(), 3); @@ -714,7 +683,7 @@ pub mod tests { init!("true"); let cred: Credential = Credential::from_str(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); assert!(cred.payment_info.is_none()); - assert_eq!(cred.submit_payment().err(), Some(CredentialError::NoPaymentInformation())); + assert_eq!(cred.submit_payment().unwrap_err().kind(), VcxErrorKind::NoPaymentInformation); } #[test] @@ -733,7 +702,7 @@ pub mod tests { let handle2 = from_string(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); assert!(!is_payment_required(handle2).unwrap()); let invalid_handle = 12345; - assert_eq!(is_payment_required(invalid_handle).err(), Some(CredentialError::InvalidHandle())); + assert_eq!(is_payment_required(invalid_handle).unwrap_err().kind(), VcxErrorKind::InvalidCredentialHandle); } #[test] diff --git a/vcx/libvcx/src/credential_def.rs b/vcx/libvcx/src/credential_def.rs index a027430018..625b66b939 100644 --- a/vcx/libvcx/src/credential_def.rs +++ b/vcx/libvcx/src/credential_def.rs @@ -1,18 +1,17 @@ -extern crate serde_json; -extern crate rand; -extern crate libc; +use serde_json; -use utils::error; -use utils::libindy::payments::{PaymentTxn}; -use utils::libindy::anoncreds; -use error::cred_def::CredDefError; use object_cache::ObjectCache; +use messages::ObjectWithVersion; +use error::prelude::*; +use utils::constants::DEFAULT_SERIALIZE_VERSION; +use utils::libindy::payments::PaymentTxn; +use utils::libindy::anoncreds; lazy_static! { static ref CREDENTIALDEF_MAP: ObjectCache = Default::default(); } -#[derive(Deserialize, Debug, Serialize, PartialEq)] +#[derive(Clone, Deserialize, Debug, Serialize, PartialEq)] pub struct CredentialDef { id: String, tag: String, @@ -35,40 +34,26 @@ pub struct RevocationDetails { pub max_creds: Option, } -impl Default for CredentialDef { - fn default() -> CredentialDef { - CredentialDef { - id: String::new(), - tag: String::new(), - name: String::new(), - source_id: String::new(), - issuer_did: None, - cred_def_payment_txn: None, - rev_reg_def_payment_txn: None, - rev_reg_delta_payment_txn: None, - rev_reg_id: None, - rev_reg_def: None, - rev_reg_entry: None, - tails_file: None, - } - } -} - impl CredentialDef { - - pub fn from_str(input: &str) -> Result { - CredentialDef::from_string_with_version(&input).or(Err(CredDefError::CreateCredDefError())) + pub fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.map(VcxErrorKind::CreateCredDef,"Cannot deserialize CredentialDefinition")) } - pub fn to_string(&self) -> String { self.to_string_with_version() } + pub fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize CredentialDefinition")) + } pub fn get_source_id(&self) -> &String { &self.source_id } - pub fn get_rev_reg_id(&self) -> Option { self.rev_reg_id.clone() } + pub fn get_rev_reg_id(&self) -> Option<&String> { self.rev_reg_id.as_ref() } - pub fn get_tails_file(&self) -> Option {self.tails_file.clone() } + pub fn get_tails_file(&self) -> Option<&String> { self.tails_file.as_ref() } - pub fn get_rev_reg_def(&self) -> Option { self.rev_reg_def.clone() } + pub fn get_rev_reg_def(&self) -> Option<&String> { self.rev_reg_def.as_ref() } pub fn get_cred_def_id(&self) -> &String { &self.id } @@ -76,25 +61,14 @@ impl CredentialDef { pub fn set_source_id(&mut self, source_id: String) { self.source_id = source_id.clone(); } - fn get_cred_def_payment_txn(&self) -> Result { Ok(self.cred_def_payment_txn.clone().ok_or(error::NOT_READY.code_num)?) } + fn get_cred_def_payment_txn(&self) -> VcxResult { + self.cred_def_payment_txn.clone() + .ok_or(VcxError::from(VcxErrorKind::NoPaymentInformation)) + } fn get_rev_reg_def_payment_txn(&self) -> Option { self.rev_reg_def_payment_txn.clone() } fn get_rev_reg_delta_payment_txn(&self) -> Option { self.rev_reg_delta_payment_txn.clone() } - - fn to_string_with_version(&self) -> String { - json!({ - "version": "1.0", - "data": json!(self), - }).to_string() - } - - fn from_string_with_version(data: &str) -> Result { - let values:serde_json::Value = serde_json::from_str(data).or(Err(CredDefError::CommonError(error::INVALID_JSON.code_num)))?; - let version = values["version"].to_string(); - let data = values["data"].to_string(); - serde_json::from_str(&data).or(Err(CredDefError::CreateCredDefError())) - } } pub fn create_new_credentialdef(source_id: String, @@ -102,31 +76,29 @@ pub fn create_new_credentialdef(source_id: String, issuer_did: String, schema_id: String, tag: String, - revocation_details: String) -> Result { + revocation_details: String) -> VcxResult { trace!("create_new_credentialdef >>> source_id: {}, name: {}, issuer_did: {}, schema_id: {}, revocation_details: {}", source_id, name, issuer_did, schema_id, revocation_details); let revocation_details: RevocationDetails = serde_json::from_str(&revocation_details) - .or(Err(CredDefError::InvalidRevocationDetails()))?; + .to_vcx(VcxErrorKind::InvalidRevocationDetails, "Cannot deserialize RevocationDeltas")?; - let (_, schema_json) = anoncreds::get_schema_json(&schema_id) - .map_err(|x| CredDefError::CommonError(x))?; + let (_, schema_json) = anoncreds::get_schema_json(&schema_id)?; // Creates Credential Definition in both wallet and on ledger let (id, cred_def_payment_txn) = anoncreds::create_cred_def(&issuer_did, - &schema_json, - &tag, - None, - revocation_details.support_revocation) - .map_err(|err| { - if err == error::CREDENTIAL_DEF_ALREADY_CREATED.code_num { - error!("Credential Definition for issuer_did {} already in wallet", issuer_did); - CredDefError::CredDefAlreadyCreatedError() - } else { - error!("{} with: {}", error::CREATE_CREDENTIAL_DEF_ERR.message, err); - CredDefError::CreateCredDefError() - } - })?; + &schema_json, + &tag, + None, + revocation_details.support_revocation).map_err(|err| { + if err.kind() == VcxErrorKind::CredDefAlreadyCreated { + error!("Credential Definition for issuer_did {} already in wallet", issuer_did); + err + } else { + error!("{}", err); + VcxError::from_msg(VcxErrorKind::CreateCredDef, err) + } + })?; // Creates Revocation Definition in wallet and on ledger // Posts Revocation Delta to Ledger @@ -136,25 +108,25 @@ pub fn create_new_credentialdef(source_id: String, let tails_file = revocation_details .tails_file .as_ref() - .ok_or(CredDefError::InvalidRevocationDetails())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Invalid RevocationDetails: `tails_file` field not found"))?; let max_creds = revocation_details .max_creds - .ok_or(CredDefError::InvalidRevocationDetails())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Invalid RevocationDetails: `max_creds` field not found"))?; let (rev_reg_id, rev_reg_def, rev_reg_entry, rev_def_payment) = anoncreds::create_rev_reg_def(&issuer_did, &id, &tails_file, max_creds) - .or(Err(CredDefError::CreateRevRegDefError()))?; + .map_err(|err| err.map(VcxErrorKind::CreateCredDef, "Cannot create CredentialDefinition"))?; let (delta_payment, _) = anoncreds::post_rev_reg_delta(&issuer_did, &rev_reg_id, &rev_reg_entry) - .or(Err(CredDefError::InvalidRevocationEntry()))?; + .map_err(|err| err.map(VcxErrorKind::InvalidRevocationEntry, "Cannot post RevocationEntry"))?; (Some(rev_reg_id), Some(rev_reg_def), Some(rev_reg_entry), rev_def_payment, delta_payment) } _ => (None, None, None, None, None), }; - let new_cred_def = CredentialDef { + let cred_def = CredentialDef { source_id, name, tag, @@ -169,104 +141,82 @@ pub fn create_new_credentialdef(source_id: String, tails_file: revocation_details.tails_file, }; - let new_handle = CREDENTIALDEF_MAP.add(new_cred_def).map_err(|key|CredDefError::CreateCredDefError())?; + let handle = CREDENTIALDEF_MAP.add(cred_def).or(Err(VcxError::from(VcxErrorKind::CreateCredDef)))?; - Ok(new_handle) + Ok(handle) } pub fn is_valid_handle(handle: u32) -> bool { CREDENTIALDEF_MAP.has_handle(handle) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { CREDENTIALDEF_MAP.get(handle, |cd| { - Ok(CredentialDef::to_string_with_version(&cd)) + cd.to_string() }) } -pub fn from_string(credentialdef_data: &str) -> Result { - let derived_credentialdef: CredentialDef = CredentialDef::from_str(credentialdef_data)?; - let source_id = derived_credentialdef.source_id.clone(); - let new_handle = CREDENTIALDEF_MAP.add(derived_credentialdef).map_err(|ec|CredDefError::CommonError(ec))?; - - Ok(new_handle) +pub fn from_string(data: &str) -> VcxResult { + let cred_def: CredentialDef = CredentialDef::from_str(data)?; + CREDENTIALDEF_MAP.add(cred_def) } -pub fn get_source_id(handle: u32) -> Result { - CREDENTIALDEF_MAP.get(handle,|c| { +pub fn get_source_id(handle: u32) -> VcxResult { + CREDENTIALDEF_MAP.get(handle, |c| { Ok(c.get_source_id().clone()) - }).map_err(|ec|CredDefError::CommonError(ec)) + }) } -pub fn get_cred_def_payment_txn(handle: u32) -> Result { - CREDENTIALDEF_MAP.get(handle,|c| { +pub fn get_cred_def_payment_txn(handle: u32) -> VcxResult { + CREDENTIALDEF_MAP.get(handle, |c| { c.get_cred_def_payment_txn() - }).or(Err(CredDefError::NoPaymentInformation())) + }) } -pub fn get_cred_def_id(handle: u32) -> Result { - CREDENTIALDEF_MAP.get(handle,|c| { +pub fn get_cred_def_id(handle: u32) -> VcxResult { + CREDENTIALDEF_MAP.get(handle, |c| { Ok(c.get_cred_def_id().clone()) - }).map_err(|ec|CredDefError::CommonError(ec)) + }) } -pub fn get_rev_reg_id(handle: u32) -> Result, CredDefError> { - CREDENTIALDEF_MAP.get(handle,|c| { - Ok(c.get_rev_reg_id().clone()) - }).map_err(|ec|CredDefError::CommonError(ec)) +pub fn get_rev_reg_id(handle: u32) -> VcxResult> { + CREDENTIALDEF_MAP.get(handle, |c| { + Ok(c.get_rev_reg_id().cloned()) + }) } -pub fn get_tails_file(handle: u32) -> Result, CredDefError> { - CREDENTIALDEF_MAP.get(handle,|c| { - Ok(c.get_tails_file().clone()) - }).map_err(|ec|CredDefError::CommonError(ec)) +pub fn get_tails_file(handle: u32) -> VcxResult> { + CREDENTIALDEF_MAP.get(handle, |c| { + Ok(c.get_tails_file().cloned()) + }) } -pub fn get_rev_reg_def(handle: u32) -> Result, CredDefError> { - CREDENTIALDEF_MAP.get(handle,|c| { - Ok(c.get_rev_reg_def().clone()) - }).map_err(|ec|CredDefError::CommonError(ec)) +pub fn get_rev_reg_def(handle: u32) -> VcxResult> { + CREDENTIALDEF_MAP.get(handle, |c| { + Ok(c.get_rev_reg_def().cloned()) + }) } -pub fn get_rev_reg_def_payment_txn(handle: u32) -> Result, CredDefError> { - CREDENTIALDEF_MAP.get(handle,|c| { +pub fn get_rev_reg_def_payment_txn(handle: u32) -> VcxResult> { + CREDENTIALDEF_MAP.get(handle, |c| { Ok(c.get_rev_reg_def_payment_txn()) - }).map_err(|ec|CredDefError::CommonError(ec)) + }) } -pub fn get_rev_reg_delta_payment_txn(handle: u32) -> Result, CredDefError> { - CREDENTIALDEF_MAP.get(handle,|c| { +pub fn get_rev_reg_delta_payment_txn(handle: u32) -> VcxResult> { + CREDENTIALDEF_MAP.get(handle, |c| { Ok(c.get_rev_reg_delta_payment_txn()) - }).map_err(|ec|CredDefError::CommonError(ec)) -} - -pub fn release(handle: u32) -> Result<(), CredDefError> { - match CREDENTIALDEF_MAP.release(handle) { - Ok(_) => Ok(()), - Err(_) => Err(CredDefError::InvalidHandle()), - } + }) } -pub fn find_handle(cred_def_id: &str) -> Result { - let mut handles = Vec::new(); - - for handle in CREDENTIALDEF_MAP.store.lock().unwrap().iter() { - handles.push(handle.0.clone()); - } - for handle in handles.iter() { - let id = get_cred_def_id(*handle).unwrap(); - println!("id: {}", id); - } - - Ok(error::SUCCESS.code_num) +pub fn release(handle: u32) -> VcxResult<()> { + CREDENTIALDEF_MAP.release(handle) + .or(Err(VcxError::from(VcxErrorKind::InvalidCredDefHandle))) } pub fn release_all() { - match CREDENTIALDEF_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + CREDENTIALDEF_MAP.drain().ok(); } #[cfg(test)] @@ -334,8 +284,7 @@ pub mod tests { let payment = serde_json::to_string(&get_cred_def_payment_txn(handle).unwrap()).unwrap(); assert!(payment.len() > 0); - find_handle("123").unwrap(); -} + } #[test] fn test_get_credential_def_by_send_request_fails() { @@ -370,12 +319,12 @@ pub mod tests { let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let rc = create_new_credentialdef("1".to_string(), - wallet_name.to_string(), - did, - schema_id, - "tag_1".to_string(), - r#"{"support_revocation":true}"#.to_string()); - assert_eq!(rc, Err(CredDefError::InvalidRevocationDetails())); + wallet_name.to_string(), + did, + schema_id, + "tag_1".to_string(), + r#"{"support_revocation":true}"#.to_string()); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::InvalidRevocationDetails); } #[cfg(feature = "pool_tests")] @@ -454,7 +403,7 @@ pub mod tests { "tag_1".to_string(), r#"{"support_revocation":false}"#.to_string()); - assert_eq!(rc.err(), Some(CredDefError::CredDefAlreadyCreatedError())); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::CredDefAlreadyCreated); } #[test] @@ -484,8 +433,8 @@ pub mod tests { let new_credentialdef_data = to_string(new_handle).unwrap(); let credentialdef1: CredentialDef = CredentialDef::from_str(&credentialdef_data).unwrap(); let credentialdef2: CredentialDef = CredentialDef::from_str(&new_credentialdef_data).unwrap(); - assert_eq!(credentialdef1,credentialdef2); - assert_eq!(CredentialDef::from_str("{}").err(), Some(CredDefError::CreateCredDefError())); + assert_eq!(credentialdef1, credentialdef2); + assert_eq!(CredentialDef::from_str("{}").unwrap_err().kind(), VcxErrorKind::CreateCredDef); } #[test] @@ -497,11 +446,11 @@ pub mod tests { let h4 = create_new_credentialdef("SourceId".to_string(), CREDENTIAL_DEF_NAME.to_string(), ISSUER_DID.to_string(), SCHEMA_ID.to_string(), "tag".to_string(), "{}".to_string()).unwrap(); let h5 = create_new_credentialdef("SourceId".to_string(), CREDENTIAL_DEF_NAME.to_string(), ISSUER_DID.to_string(), SCHEMA_ID.to_string(), "tag".to_string(), "{}".to_string()).unwrap(); release_all(); - assert_eq!(release(h1),Err(CredDefError::InvalidHandle())); - assert_eq!(release(h2),Err(CredDefError::InvalidHandle())); - assert_eq!(release(h3),Err(CredDefError::InvalidHandle())); - assert_eq!(release(h4),Err(CredDefError::InvalidHandle())); - assert_eq!(release(h5),Err(CredDefError::InvalidHandle())); + assert_eq!(release(h1).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); + assert_eq!(release(h2).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); + assert_eq!(release(h3).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); + assert_eq!(release(h4).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); + assert_eq!(release(h5).unwrap_err().kind(), VcxErrorKind::InvalidCredDefHandle); } #[test] diff --git a/vcx/libvcx/src/credential_request.rs b/vcx/libvcx/src/credential_request.rs index 2b768f526b..d6f85f3b62 100644 --- a/vcx/libvcx/src/credential_request.rs +++ b/vcx/libvcx/src/credential_request.rs @@ -1,9 +1,3 @@ -extern crate serde_json; - -static ISSUER_DID: &'static str = "issuer_did"; -static SEQUENCE_NUMBER: &'static str = "schema_seq_no"; -static BLINDED_MS: &'static str = "blinded_ms"; -static PROVER_DID: &'static str = "prover_did"; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct CredentialRequest { @@ -38,6 +32,7 @@ impl CredentialRequest { #[cfg(test)] mod tests { use super::*; + use serde_json; use utils::constants::{CREDENTIAL_REQ_STRING, CRED_REQ, CRED_REQ_META}; static TEMP_ISSUER_DID: &'static str = "4reqXeZVm7JZAffAoaNLsb"; diff --git a/vcx/libvcx/src/disclosed_proof.rs b/vcx/libvcx/src/disclosed_proof.rs index d8c92b5132..23ad18642a 100644 --- a/vcx/libvcx/src/disclosed_proof.rs +++ b/vcx/libvcx/src/disclosed_proof.rs @@ -1,30 +1,26 @@ -extern crate serde_json; +use serde_json; +use serde_json::Value; use std::collections::HashMap; +use time; + use object_cache::ObjectCache; use api::VcxStateType; -use utils::error; use connection; use messages; -use messages::GeneralMessage; -use messages::RemoteMessageType; +use messages::{GeneralMessage, RemoteMessageType, ObjectWithVersion}; use messages::payload::{Payloads, PayloadKinds, Thread}; use messages::proofs::proof_message::ProofMessage; use messages::proofs::proof_request::{ProofRequestMessage, ProofRequestData, NonRevokedInterval}; -use time; - -use utils::libindy::anoncreds; -use utils::libindy::anoncreds::{get_rev_reg_def_json, get_rev_reg_delta_json}; - +use messages::get_message::Message; +use error::prelude::*; use settings; -use utils::httpclient; +use utils::{httpclient, error}; use utils::constants::{DEFAULT_SERIALIZE_VERSION, CREDS_FROM_PROOF_REQ, DEFAULT_GENERATED_PROOF}; use utils::libindy::cache::{get_rev_reg_cache, set_rev_reg_cache, RevRegCache, RevState}; +use utils::libindy::anoncreds; +use utils::libindy::anoncreds::{get_rev_reg_def_json, get_rev_reg_delta_json}; -use serde_json::Value; - -use error::ToErrorCode; -use error::proof::ProofError; lazy_static! { static ref HANDLE_MAP: ObjectCache = Default::default(); @@ -86,13 +82,11 @@ pub struct CredInfo { pub timestamp: Option } -fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) - -> Result, ProofError> { - +fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) -> VcxResult> { let mut rtn = Vec::new(); let credentials: Value = serde_json::from_str(credentials) - .or(Err(ProofError::InvalidJson()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize credentials: {}", err)))?; if let Value::Object(ref attrs) = credentials["attrs"] { for (requested_attr, value) in attrs { @@ -100,7 +94,6 @@ fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) (value["credential"]["cred_info"]["referent"].as_str(), value["credential"]["cred_info"]["schema_id"].as_str(), value["credential"]["cred_info"]["cred_def_id"].as_str()) { - let rev_reg_id = value["credential"]["cred_info"]["rev_reg_id"] .as_str() .map(|x| x.to_string()); @@ -126,31 +119,24 @@ fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) tails_file, } ); - } else { return Err(ProofError::InvalidCredData()); } + } else { return Err(VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, "Cannot get identifiers")); } } } Ok(rtn) } -fn _get_revocation_interval(attr_name: &str, proof_req: &ProofRequestData) - -> Result, ProofError> { - if let Some(ref attr) = proof_req.requested_attributes.get(attr_name) { - if let Some(ref interval) = attr.non_revoked { - return Ok(Some(NonRevokedInterval { from: interval.from, to: interval.to })); - } else if let Some(ref interval) = proof_req.non_revoked { - return Ok(Some(NonRevokedInterval { from: interval.from, to: interval.to })); - } +fn _get_revocation_interval(attr_name: &str, proof_req: &ProofRequestData) -> VcxResult> { + let attr = proof_req.requested_attributes.get(attr_name) + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, format!("Attribute not found for: {}", attr_name)))?; - return Ok(None); - } - // Todo: Handle case for predicates + Ok(attr.non_revoked.clone().or(proof_req.non_revoked.clone().or(None))) - Err(ProofError::InvalidCredData()) + // Todo: Handle case for predicates } // Also updates timestamp in credentials_identifiers -fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result { +fn build_rev_states_json(credentials_identifiers: &mut Vec) -> VcxResult { let mut rtn: Value = json!({}); let mut timestamps: HashMap = HashMap::new(); @@ -177,14 +163,13 @@ fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result< _ => None }; - let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id) - .map_err(|e| ProofError::CommonError(e))?; + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id)?; let (rev_reg_id, rev_reg_delta_json, timestamp) = get_rev_reg_delta_json( &rev_reg_id, from, to - ).map_err(|e| ProofError::CommonError(e))?; + )?; let rev_state_json = anoncreds::libindy_prover_update_revocation_state( &rev_reg_def_json, @@ -192,7 +177,7 @@ fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result< &rev_reg_delta_json, &cred_rev_id, &tails_file - ).map_err(|e| ProofError::CommonError(e))?; + )?; if timestamp > cached_rev_state.timestamp { let new_cache = RevRegCache { @@ -207,21 +192,20 @@ fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result< (rev_state_json, timestamp) } } else { - let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id) - .map_err(|e| ProofError::CommonError(e))?; + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id)?; let (rev_reg_id, rev_reg_delta_json, timestamp) = get_rev_reg_delta_json( &rev_reg_id, None, to - ).map_err(|e| ProofError::CommonError(e))?; + )?; let rev_state_json = anoncreds::libindy_prover_create_revocation_state( &rev_reg_def_json, &rev_reg_delta_json, &cred_rev_id, &tails_file - ).map_err(|e| ProofError::CommonError(e))?; + )?; let new_cache = RevRegCache { rev_state: Some(RevState { @@ -235,7 +219,7 @@ fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result< }; let rev_state_json: Value = serde_json::from_str(&rev_state_json) - .or(Err(ProofError::InvalidJson()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize RevocationState: {}", err)))?; // TODO: proover should be able to create multiple states of same revocation policy for different timestamps // see ticket IS-1108 @@ -248,7 +232,7 @@ fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result< // If the rev_reg_id is already in the map, timestamp may not be updated on cred_info if cred_info.timestamp.is_none() { - cred_info.timestamp = timestamps.get(rev_reg_id).map(|x| x.clone()); + cred_info.timestamp = timestamps.get(rev_reg_id).cloned(); } } } @@ -268,31 +252,30 @@ impl DisclosedProof { self.state = state } - fn retrieve_credentials(&self) -> Result { + fn retrieve_credentials(&self) -> VcxResult { trace!("DisclosedProof::set_state >>>"); if settings::test_indy_mode_enabled() { return Ok(CREDS_FROM_PROOF_REQ.to_string()); } let proof_req = self.proof_request .as_ref() - .ok_or(ProofError::ProofNotReadyError())?; + .ok_or(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot get proot request"))?; let indy_proof_req = serde_json::to_string(&proof_req.proof_request_data) - .or(Err(ProofError::InvalidJson()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize proof request: {}", err)))?; anoncreds::libindy_prover_get_credentials_for_proof_req(&indy_proof_req) - .map_err(|err| ProofError::CommonError(err)) } - fn build_schemas_json(&self, credentials_identifiers: &Vec) -> Result { + fn build_schemas_json(&self, credentials_identifiers: &Vec) -> VcxResult { let mut rtn: Value = json!({}); for ref cred_info in credentials_identifiers { if rtn.get(&cred_info.schema_id).is_none() { let (_, schema_json) = anoncreds::get_schema_json(&cred_info.schema_id) - .or(Err(ProofError::InvalidSchema()))?; + .map_err(|err| err.map(VcxErrorKind::InvalidSchema, "Cannot get schema"))?; let schema_json = serde_json::from_str(&schema_json) - .or(Err(ProofError::InvalidSchema()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidSchema, format!("Cannot deserialize schema: {}", err)))?; rtn[cred_info.schema_id.to_owned()] = schema_json; } @@ -300,16 +283,16 @@ impl DisclosedProof { Ok(rtn.to_string()) } - fn build_cred_def_json(&self, credentials_identifiers: &Vec) -> Result { + fn build_cred_def_json(&self, credentials_identifiers: &Vec) -> VcxResult { let mut rtn: Value = json!({}); for ref cred_info in credentials_identifiers { if rtn.get(&cred_info.cred_def_id).is_none() { let (_, credential_def) = anoncreds::get_cred_def_json(&cred_info.cred_def_id) - .or(Err(ProofError::InvalidCredData()))?; + .map_err(|err| err.map(VcxErrorKind::InvalidProofCredentialData, "Cannot get credential definition"))?; let credential_def = serde_json::from_str(&credential_def) - .or(Err(ProofError::InvalidCredData()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, format!("Cannot deserialize credential definition: {}", err)))?; rtn[cred_info.cred_def_id.to_owned()] = credential_def; } @@ -317,9 +300,7 @@ impl DisclosedProof { Ok(rtn.to_string()) } - fn build_requested_credentials_json(&self, - credentials_identifiers: &Vec, - self_attested_attrs: &str) -> Result { + fn build_requested_credentials_json(&self, credentials_identifiers: &Vec, self_attested_attrs: &str) -> VcxResult { let mut rtn: Value = json!({ "self_attested_attributes":{}, "requested_attributes":{}, @@ -335,30 +316,27 @@ impl DisclosedProof { } let self_attested_attrs: Value = serde_json::from_str(self_attested_attrs) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize self attested attributes: {}", err)))?; rtn["self_attested_attributes"] = self_attested_attrs; Ok(rtn.to_string()) } - fn generate_proof(&mut self, credentials: &str, self_attested_attrs: &str) -> Result { + fn generate_proof(&mut self, credentials: &str, self_attested_attrs: &str) -> VcxResult { trace!("DisclosedProof::generate_proof >>> credentials: {}, self_attested_attrs: {}", credentials, self_attested_attrs); debug!("generating proof {}", self.source_id); if settings::test_indy_mode_enabled() { return Ok(error::SUCCESS.code_num); } - let proof_req = self.proof_request.as_ref() - .ok_or(ProofError::CreateProofError())?; - let proof_req_data_json = serde_json::to_string(&proof_req.proof_request_data) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + let proof_req = self.proof_request.as_ref().ok_or(VcxError::from_msg(VcxErrorKind::CreateProof, "Cannot get proof request"))?; + let proof_req_data_json = serde_json::to_string(&proof_req.proof_request_data) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof request: {}", err)))?; - let mut credentials_identifiers = credential_def_identifiers(credentials, - &proof_req.proof_request_data)?; + let mut credentials_identifiers = credential_def_identifiers(credentials, &proof_req.proof_request_data)?; let revoc_states_json = build_rev_states_json(&mut credentials_identifiers)?; - let requested_credentials = self.build_requested_credentials_json(&credentials_identifiers, - self_attested_attrs)?; + let requested_credentials = self.build_requested_credentials_json(&credentials_identifiers, self_attested_attrs)?; let schemas_json = self.build_schemas_json(&credentials_identifiers)?; let credential_defs_json = self.build_cred_def_json(&credentials_identifiers)?; @@ -368,7 +346,7 @@ impl DisclosedProof { &self.link_secret_alias, &schemas_json, &credential_defs_json, - Some(&revoc_states_json)).map_err(|ec| ProofError::CommonError(ec))?; + Some(&revoc_states_json))?; let mut proof_msg = ProofMessage::new(); proof_msg.libindy_proof = proof; self.proof = Some(proof_msg); @@ -376,18 +354,17 @@ impl DisclosedProof { Ok(error::SUCCESS.code_num) } - fn send_proof(&mut self, connection_handle: u32) -> Result { + fn send_proof(&mut self, connection_handle: u32) -> VcxResult { trace!("DisclosedProof::send_proof >>> connection_handle: {}", connection_handle); debug!("sending proof {} via connection: {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); // There feels like there's a much more rusty way to do the below. - self.my_did = Some(connection::get_pw_did(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - self.my_vk = Some(connection::get_pw_verkey(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - self.agent_did = Some(connection::get_agent_did(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - self.agent_vk = Some(connection::get_agent_verkey(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - self.their_did = Some(connection::get_their_pw_did(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - self.their_vk = Some(connection::get_their_pw_verkey(connection_handle).or(Err(ProofError::ProofConnectionError()))?); - + self.my_did = Some(connection::get_pw_did(connection_handle)?); + self.my_vk = Some(connection::get_pw_verkey(connection_handle)?); + self.agent_did = Some(connection::get_agent_did(connection_handle)?); + self.agent_vk = Some(connection::get_agent_verkey(connection_handle)?); + self.their_did = Some(connection::get_their_pw_did(connection_handle)?); + self.their_vk = Some(connection::get_their_pw_verkey(connection_handle)?); debug!("verifier_did: {:?} -- verifier_vk: {:?} -- agent_did: {:?} -- agent_vk: {:?} -- remote_vk: {:?}", self.my_did, @@ -396,20 +373,21 @@ impl DisclosedProof { self.their_vk, self.my_vk); - self.their_did.as_ref().ok_or(ProofError::ProofConnectionError())?; - let local_their_vk = self.their_vk.as_ref().ok_or(ProofError::ProofConnectionError())?; - let local_agent_did = self.agent_did.as_ref().ok_or(ProofError::ProofConnectionError())?; - let local_agent_vk = self.agent_vk.as_ref().ok_or(ProofError::ProofConnectionError())?; - let local_my_did = self.my_did.as_ref().ok_or(ProofError::ProofConnectionError())?; - let local_my_vk = self.my_vk.as_ref().ok_or(ProofError::ProofConnectionError())?; + self.their_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; + let local_their_vk = self.their_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; + let local_agent_did = self.agent_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; + let local_agent_vk = self.agent_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; + let local_my_did = self.my_did.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; + let local_my_vk = self.my_vk.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConnectionHandle))?; - let proof_req = self.proof_request.as_ref().ok_or(ProofError::CreateProofError())?; - let ref_msg_uid = proof_req.msg_ref_id.as_ref().ok_or(ProofError::CreateProofError())?; + let proof_req = self.proof_request.as_ref().ok_or(VcxError::from(VcxErrorKind::CreateProof))?; + let ref_msg_uid = proof_req.msg_ref_id.as_ref().ok_or(VcxError::from(VcxErrorKind::CreateProof))?; let proof = match settings::test_indy_mode_enabled() { false => { - let proof: &ProofMessage = self.proof.as_ref().ok_or(ProofError::CreateProofError())?; - serde_json::to_string(&proof).or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))? + let proof: &ProofMessage = self.proof.as_ref().ok_or(VcxError::from(VcxErrorKind::CreateProof))?; + serde_json::to_string(&proof) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof: {}", err)))? } true => DEFAULT_GENERATED_PROOF.to_string(), }; @@ -423,49 +401,46 @@ impl DisclosedProof { .msg_type(&RemoteMessageType::Proof)? .agent_did(local_agent_did)? .agent_vk(local_agent_vk)? - .edge_agent_payload(&local_my_vk, &local_their_vk, &proof, PayloadKinds::Proof, self.thread.clone()).or(Err(ProofError::ProofConnectionError()))? + .edge_agent_payload(&local_my_vk, &local_their_vk, &proof, PayloadKinds::Proof, self.thread.clone()) + .map_err(|err| VcxError::from_msg(VcxErrorKind::GeneralConnectionError, format!("Cannot encrypt payload: {}", err)))? .ref_msg_id(ref_msg_uid)? .send_secure() - .map_err(|err| { - warn!("could not send proof: {}", err); - err - })?; + .map_err(|err| err.extend("Could not send proof"))?; self.state = VcxStateType::VcxStateAccepted; return Ok(error::SUCCESS.code_num); } fn set_source_id(&mut self, id: &str) { self.source_id = id.to_string(); } + fn get_source_id(&self) -> &String { &self.source_id } - fn to_string(&self) -> String { + + fn to_string(&self) -> VcxResult { trace!("DisclosedProof::to_string >>>"); - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json!(self), - }).to_string() + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize DisclosedProof")) } - fn from_str(s: &str) -> Result { - trace!("DisclosedProof::from_str >>> data: {}", s); - let s: Value = serde_json::from_str(&s) - .or(Err(ProofError::InvalidJson()))?; - let proof: DisclosedProof = serde_json::from_value(s["data"].clone()) - .or(Err(ProofError::InvalidJson()))?; - Ok(proof) + fn from_str(data: &str) -> VcxResult { + trace!("DisclosedProof::from_str >>> data: {}", data); + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize DisclosedProof")) } } //******************************************** // HANDLE FUNCTIONS //******************************************** -fn handle_err(code_num: u32) -> u32 { - if code_num == error::INVALID_OBJ_HANDLE.code_num { - error::INVALID_DISCLOSED_PROOF_HANDLE.code_num +fn handle_err(err: VcxError) -> VcxError { + if err.kind() == VcxErrorKind::InvalidHandle { + VcxError::from(VcxErrorKind::InvalidDisclosedProofHandle) } else { - code_num + err } } -pub fn create_proof(source_id: &str, proof_req: &str) -> Result { +pub fn create_proof(source_id: &str, proof_req: &str) -> VcxResult { trace!("create_proof >>> source_id: {}, proof_req: {}", source_id, proof_req); debug!("creating disclosed proof with id: {}", source_id); @@ -474,70 +449,66 @@ pub fn create_proof(source_id: &str, proof_req: &str) -> Result new_proof.set_source_id(source_id); new_proof.set_proof_request(serde_json::from_str(proof_req) - .map_err(|_| ProofError::CommonError(error::INVALID_JSON.code_num))?); + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize proof request: {}", err)))?); new_proof.set_state(VcxStateType::VcxStateRequestReceived); - Ok(HANDLE_MAP.add(new_proof).map_err(|ec| ProofError::CommonError(ec))?) + HANDLE_MAP.add(new_proof) } -pub fn get_state(handle: u32) -> Result { +pub fn get_state(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_state()) }).map_err(handle_err) } // update_state is just the same as get_state for disclosed_proof -pub fn update_state(handle: u32) -> Result { +pub fn update_state(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_state()) }) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { - Ok(DisclosedProof::to_string(&obj)) + DisclosedProof::to_string(&obj) }) } -pub fn from_string(proof_data: &str) -> Result { - let derived_proof: DisclosedProof = DisclosedProof::from_str(proof_data) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; +pub fn from_string(proof_data: &str) -> VcxResult { + let derived_proof: DisclosedProof = DisclosedProof::from_str(proof_data)?; - let new_handle = HANDLE_MAP.add(derived_proof).map_err(|ec| ProofError::CommonError(ec))?; + let new_handle = HANDLE_MAP.add(derived_proof)?; info!("inserting handle {} into proof table", new_handle); Ok(new_handle) } -pub fn release(handle: u32) -> Result<(), u32> { +pub fn release(handle: u32) -> VcxResult<()> { HANDLE_MAP.release(handle).map_err(handle_err) } pub fn release_all() { - match HANDLE_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + HANDLE_MAP.drain().ok(); } -pub fn send_proof(handle: u32, connection_handle: u32) -> Result { +pub fn send_proof(handle: u32, connection_handle: u32) -> VcxResult { HANDLE_MAP.get_mut(handle, |obj| { - obj.send_proof(connection_handle).map_err(|e| e.to_error_code()) - }).map_err(|ec| ProofError::CommonError(ec)) + obj.send_proof(connection_handle) + }) } -pub fn generate_proof(handle: u32, credentials: String, self_attested_attrs: String) -> Result { +pub fn generate_proof(handle: u32, credentials: String, self_attested_attrs: String) -> VcxResult { HANDLE_MAP.get_mut(handle, |obj| { - obj.generate_proof(&credentials, &self_attested_attrs).map_err(|e| e.to_error_code()) - }).map_err(|ec| ProofError::CommonError(ec)) + obj.generate_proof(&credentials, &self_attested_attrs) + }) } -pub fn retrieve_credentials(handle: u32) -> Result { +pub fn retrieve_credentials(handle: u32) -> VcxResult { HANDLE_MAP.get_mut(handle, |obj| { - obj.retrieve_credentials().map_err(|e| e.to_error_code()) - }).map_err(|ec| ProofError::CommonError(ec)) + obj.retrieve_credentials() + }) } pub fn is_valid_handle(handle: u32) -> bool { @@ -545,13 +516,13 @@ pub fn is_valid_handle(handle: u32) -> bool { } //TODO one function with credential -pub fn get_proof_request(connection_handle: u32, msg_id: &str) -> Result { +pub fn get_proof_request(connection_handle: u32, msg_id: &str) -> VcxResult { trace!("get_proof_request >>> connection_handle: {}, msg_id: {}", connection_handle, msg_id); - let my_did = connection::get_pw_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let agent_did = connection::get_agent_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let agent_vk = connection::get_agent_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; + let my_did = connection::get_pw_did(connection_handle)?; + let my_vk = connection::get_pw_verkey(connection_handle)?; + let agent_did = connection::get_agent_did(connection_handle)?; + let agent_vk = connection::get_agent_verkey(connection_handle)?; if settings::test_agency_mode_enabled() { httpclient::set_next_u8_response(::utils::constants::NEW_PROOF_REQUEST_RESPONSE.to_vec()); } @@ -559,33 +530,26 @@ pub fn get_proof_request(connection_handle: u32, msg_id: &str) -> Result) -> Result { +pub fn get_proof_request_messages(connection_handle: u32, match_name: Option<&str>) -> VcxResult { trace!("get_proof_request_messages >>> connection_handle: {}, match_name: {:?}", connection_handle, match_name); - let my_did = connection::get_pw_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let agent_did = connection::get_agent_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; - let agent_vk = connection::get_agent_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; + let my_did = connection::get_pw_did(connection_handle)?; + let my_vk = connection::get_pw_verkey(connection_handle)?; + let agent_did = connection::get_agent_did(connection_handle)?; + let agent_vk = connection::get_agent_verkey(connection_handle)?; if settings::test_agency_mode_enabled() { httpclient::set_next_u8_response(::utils::constants::NEW_PROOF_REQUEST_RESPONSE.to_vec()); } @@ -593,7 +557,7 @@ pub fn get_proof_request_messages(connection_handle: u32, match_name: Option<&st &my_vk, &agent_did, &agent_vk, - None).map_err(|ec| ProofError::CommonError(ec))?; + None)?; let mut messages: Vec = Default::default(); @@ -601,22 +565,31 @@ pub fn get_proof_request_messages(connection_handle: u32, match_name: Option<&st if msg.sender_did.eq(&my_did) { continue; } if msg.msg_type == RemoteMessageType::ProofReq { - let payload = msg.payload.ok_or(ProofError::CommonError(error::INVALID_HTTP_RESPONSE.code_num))?; - let (req, thread) = Payloads::decrypt(&my_vk, &payload).map_err(|ec| ProofError::CommonError(ec))?; - - let mut req: ProofRequestMessage = serde_json::from_str(&req) - .or(Err(ProofError::CommonError(error::INVALID_HTTP_RESPONSE.code_num)))?; - - req.msg_ref_id = Some(msg.uid.to_owned()); - req.thread_id = thread.and_then(|tr| tr.thid.clone()); + let req = _parse_proof_req_message(&msg, &my_vk)?; messages.push(req); } } - Ok(serde_json::to_string_pretty(&messages).or(Err(ProofError::InvalidJson()))?) + serde_json::to_string_pretty(&messages) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof request: {}", err))) +} + +fn _parse_proof_req_message(message: &Message, my_vk: &str) -> VcxResult { + let payload = message.payload.as_ref() + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Cannot get payload"))?; + + let (request, thread) = Payloads::decrypt(&my_vk, payload)?; + + let mut request: ProofRequestMessage = serde_json::from_str(&request) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, format!("Cannot deserialize proof request: {}", err)))?; + + request.msg_ref_id = Some(message.uid.to_owned()); + request.thread_id = thread.and_then(|tr| tr.thid.clone()); + + Ok(request) } -pub fn get_source_id(handle: u32) -> Result { +pub fn get_source_id(handle: u32) -> VcxResult { HANDLE_MAP.get(handle, |obj| { Ok(obj.get_source_id().clone()) }).map_err(handle_err) @@ -662,8 +635,7 @@ mod tests { #[test] fn test_create_fails() { init!("true"); - assert_eq!(create_proof("1", "{}").err(), - Some(ProofError::CommonError(error::INVALID_JSON.code_num))); + assert_eq!(create_proof("1", "{}").unwrap_err().kind(), VcxErrorKind::InvalidJson); } #[test] @@ -703,8 +675,7 @@ mod tests { #[test] fn test_deserialize_fails() { - assert_eq!(from_string("{}").err(), - Some(ProofError::CommonError(error::INVALID_JSON.code_num))); + assert_eq!(from_string("{}").unwrap_err().kind(), VcxErrorKind::InvalidJson); } #[test] @@ -712,7 +683,7 @@ mod tests { init!("true"); let proof: DisclosedProof = Default::default(); - assert_eq!(proof.build_schemas_json(&Vec::new()), Ok("{}".to_string())); + assert_eq!(proof.build_schemas_json(&Vec::new()).unwrap(), "{}".to_string()); let cred1 = CredInfo { requested_attr: "height_1".to_string(), @@ -759,8 +730,7 @@ mod tests { timestamp: None, }]; let proof: DisclosedProof = Default::default(); - assert_eq!(proof.build_schemas_json(&credential_ids).err(), - Some(ProofError::InvalidSchema())); + assert_eq!(proof.build_schemas_json(&credential_ids).unwrap_err().kind(), VcxErrorKind::InvalidSchema); } #[test] @@ -812,8 +782,7 @@ mod tests { timestamp: None, }]; let proof: DisclosedProof = Default::default(); - assert_eq!(proof.build_cred_def_json(&credential_ids).err(), - Some(ProofError::InvalidCredData())); + assert_eq!(proof.build_cred_def_json(&credential_ids).unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); } #[test] @@ -966,7 +935,7 @@ mod tests { init!("false"); let proof: DisclosedProof = Default::default(); - assert_eq!(proof.retrieve_credentials(), Err(ProofError::ProofNotReadyError())); + assert_eq!(proof.retrieve_credentials().unwrap_err().kind(), VcxErrorKind::NotReady); } #[test] @@ -1055,12 +1024,12 @@ mod tests { #[test] fn test_credential_def_identifiers_failure() { // selected credentials has incorrect json - assert_eq!(credential_def_identifiers("", &proof_req_no_interval()), Err(ProofError::InvalidJson())); + assert_eq!(credential_def_identifiers("", &proof_req_no_interval()).unwrap_err().kind(), VcxErrorKind::InvalidJson); // No Creds - assert_eq!(credential_def_identifiers("{}", &proof_req_no_interval()), Ok(Vec::new())); - assert_eq!(credential_def_identifiers(r#"{"attrs":{}}"#, &proof_req_no_interval()), Ok(Vec::new())); + assert_eq!(credential_def_identifiers("{}", &proof_req_no_interval()).unwrap(), Vec::new()); + assert_eq!(credential_def_identifiers(r#"{"attrs":{}}"#, &proof_req_no_interval()).unwrap(), Vec::new()); // missing cred info let selected_credentials: Value = json!({ @@ -1071,7 +1040,7 @@ mod tests { } }); - assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()).unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); // Optional Revocation let mut selected_credentials: Value = json!({ @@ -1138,11 +1107,11 @@ mod tests { }, "predicates":{ } }); - assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()).unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); // Schema Id is null selected_credentials["attrs"]["height_1"]["cred_info"]["schema_id"] = serde_json::Value::Null; - assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()).unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); } #[cfg(feature = "pool_tests")] @@ -1267,7 +1236,7 @@ mod tests { init!("ledger"); // empty vector - assert_eq!(build_rev_states_json(Vec::new().as_mut()), Ok("{}".to_string())); + assert_eq!(build_rev_states_json(Vec::new().as_mut()).unwrap(), "{}".to_string()); // no rev_reg_id let cred1 = CredInfo { @@ -1281,7 +1250,7 @@ mod tests { revocation_interval: None, timestamp: None, }; - assert_eq!(build_rev_states_json(vec![cred1].as_mut()), Ok("{}".to_string())); + assert_eq!(build_rev_states_json(vec![cred1].as_mut()).unwrap(), "{}".to_string()); } #[cfg(feature = "pool_tests")] @@ -1507,17 +1476,17 @@ mod tests { let proof_req: ProofRequestData = serde_json::from_value(proof_req).unwrap(); // Attribute not found in proof req - assert_eq!(_get_revocation_interval("not here", &proof_req), Err(ProofError::InvalidCredData())); + assert_eq!(_get_revocation_interval("not here", &proof_req).unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); // attribute interval overrides proof request interval let interval = Some(NonRevokedInterval { from: Some(123), to: Some(456) }); - assert_eq!(_get_revocation_interval("address1_1", &proof_req), Ok(interval)); + assert_eq!(_get_revocation_interval("address1_1", &proof_req).unwrap(), interval); // when attribute interval is None, defaults to proof req interval let interval = Some(NonRevokedInterval { from: Some(098), to: Some(123) }); - assert_eq!(_get_revocation_interval("zip_2", &proof_req), Ok(interval)); + assert_eq!(_get_revocation_interval("zip_2", &proof_req).unwrap(), interval); // No interval provided for attribute or proof req - assert_eq!(_get_revocation_interval("address1_1", &proof_req_no_interval()), Ok(None)); + assert_eq!(_get_revocation_interval("address1_1", &proof_req_no_interval()).unwrap(), None); } } diff --git a/vcx/libvcx/src/error/base.rs b/vcx/libvcx/src/error/base.rs deleted file mode 100644 index efaae4fa52..0000000000 --- a/vcx/libvcx/src/error/base.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::fmt; -use std::error::Error; - -#[derive(Debug)] -pub enum BaseError { - WalletError(String), - ConnectionError(), - GeneralError(), -} - -impl fmt::Display for BaseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - BaseError::GeneralError() => write!(f, "General Error"), - BaseError::WalletError(ref s) => write!(f, "Wallet Error: {}", s), - BaseError::ConnectionError() => write!(f, "Connection Error"), - } - } -} - -impl Error for BaseError { - fn cause(&self) -> Option<&Error> { - match *self { - BaseError::GeneralError() => None, - BaseError::WalletError(ref s) => None, - BaseError::ConnectionError() => None, - } - } - // TODO: Either implement this correctly or remove. - fn description(&self) -> &str { - match *self { - BaseError::WalletError(ref s) => "Wallet Error", - BaseError::GeneralError() => "General Base Error", - BaseError::ConnectionError() => "Connection Not Ready", - } - } -} diff --git a/vcx/libvcx/src/error/common.rs b/vcx/libvcx/src/error/common.rs deleted file mode 100644 index b28b04f643..0000000000 --- a/vcx/libvcx/src/error/common.rs +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/vcx/libvcx/src/error/connection.rs b/vcx/libvcx/src/error/connection.rs deleted file mode 100644 index 77ffee10fa..0000000000 --- a/vcx/libvcx/src/error/connection.rs +++ /dev/null @@ -1,123 +0,0 @@ - -use std::fmt; -use error::ToErrorCode; -use std::error::Error; -use utils::error::{INVALID_CONNECTION_HANDLE, - CONNECTION_ERROR, NOT_READY, - INVALID_INVITE_DETAILS, INVALID_MSGPACK, INVALID_JSON, - UNKNOWN_LIBINDY_ERROR, CANNOT_DELETE_CONNECTION, CREATE_CONNECTION_ERROR, - INVALID_WALLET_SETUP, COMMON_ERROR}; - -#[derive(Debug)] -pub enum ConnectionError { - CreateError(u32), - GeneralConnectionError(), - ConnectionNotReady(), - InviteDetailError(), - InvalidHandle(), - InvalidWalletSetup(), - InvalidMessagePack(), - InvalidJson(), - CannotDeleteConnection(), - CommonError(u32), -} - -impl From for ConnectionError { - fn from(err: u32) -> Self { - ConnectionError::CommonError(err) - } -} - -impl fmt::Display for ConnectionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ConnectionError::InvalidHandle() => write!(f, "{}", INVALID_CONNECTION_HANDLE.message), - ConnectionError::GeneralConnectionError() => write!(f, "{}", CONNECTION_ERROR.message), - ConnectionError::InviteDetailError() => write!(f, "{}", INVALID_INVITE_DETAILS.message), - ConnectionError::CreateError(key) => write!(f, "{},{}", CREATE_CONNECTION_ERROR.message, key), - ConnectionError::ConnectionNotReady() => write!(f, "{}", NOT_READY.message), - ConnectionError::InvalidMessagePack() => write!(f, "{}", INVALID_MSGPACK.message), - ConnectionError::InvalidWalletSetup() => write!(f, "{}", INVALID_WALLET_SETUP.message), - ConnectionError::CannotDeleteConnection() => write!(f, "{}", CANNOT_DELETE_CONNECTION.message), - ConnectionError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), - ConnectionError::CommonError(x) => connection_message(f, x), - } - } -} -fn connection_message(f: &mut fmt::Formatter, error_code: u32) -> fmt::Result { - if error_code == UNKNOWN_LIBINDY_ERROR.code_num { - // TODO: Make ths better, right now its just example code. - write!(f, "{}: Code: {} .. starting recovery steps.", UNKNOWN_LIBINDY_ERROR.message, UNKNOWN_LIBINDY_ERROR.code_num) - } else { - // TODO: Make ths better, right now its just example code. - write!(f, "Common Error had a value: {}.", error_code) - } -} -impl Error for ConnectionError { - fn cause(&self) -> Option<&Error> { - match *self { - ConnectionError::InvalidHandle() => None, - ConnectionError::CreateError(ref key) => None, - ConnectionError::GeneralConnectionError() => None, - ConnectionError::ConnectionNotReady() => None, - ConnectionError::InviteDetailError() => None, - ConnectionError::InvalidMessagePack() => None, - ConnectionError::InvalidWalletSetup() => None, - ConnectionError::InvalidJson() => None, - ConnectionError::CannotDeleteConnection() => None, - ConnectionError::CommonError(x) => None, - } - } - - // TODO: Either implement this correctly or remove. - fn description(&self) -> &str { - match *self { - ConnectionError::CreateError(ref key) => CREATE_CONNECTION_ERROR.message, - ConnectionError::InvalidMessagePack() => INVALID_MSGPACK.message, - ConnectionError::InvalidHandle() => INVALID_CONNECTION_HANDLE.message, - ConnectionError::GeneralConnectionError() => CONNECTION_ERROR.message, - ConnectionError::ConnectionNotReady() => NOT_READY.message, - ConnectionError::InviteDetailError() => INVALID_INVITE_DETAILS.message, - ConnectionError::InvalidWalletSetup() => INVALID_WALLET_SETUP.message, - ConnectionError::CannotDeleteConnection() => CANNOT_DELETE_CONNECTION.message, - ConnectionError::InvalidJson() => INVALID_JSON.message, - ConnectionError::CommonError(x) => COMMON_ERROR.message, - } - } -} - -impl ToErrorCode for ConnectionError { - fn to_error_code(&self) -> u32 { - match *self { - ConnectionError::InvalidHandle() => INVALID_CONNECTION_HANDLE.code_num, - ConnectionError::GeneralConnectionError() => CONNECTION_ERROR.code_num, - ConnectionError::ConnectionNotReady() => NOT_READY.code_num, - ConnectionError::InviteDetailError() => INVALID_INVITE_DETAILS.code_num, - ConnectionError::InvalidMessagePack() => INVALID_MSGPACK.code_num, - ConnectionError::CannotDeleteConnection() => CANNOT_DELETE_CONNECTION.code_num, - ConnectionError::CreateError(key) => CREATE_CONNECTION_ERROR.code_num, - ConnectionError::InvalidWalletSetup() => INVALID_WALLET_SETUP.code_num, - ConnectionError::InvalidJson() => INVALID_JSON.code_num, - ConnectionError::CommonError(x) => x, - } - } -} - -impl PartialEq for ConnectionError { - fn eq(&self, other: &ConnectionError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_to_error_code() { - assert_eq!(ConnectionError::GeneralConnectionError().to_string(), "Error with Connection"); - assert_eq!(ConnectionError::GeneralConnectionError().to_error_code(), CONNECTION_ERROR.code_num); - assert_eq!(ConnectionError::ConnectionNotReady().to_string(), "Object not ready for specified action"); - assert_eq!(ConnectionError::ConnectionNotReady().to_error_code(), NOT_READY.code_num); - - } -} \ No newline at end of file diff --git a/vcx/libvcx/src/error/cred_def.rs b/vcx/libvcx/src/error/cred_def.rs deleted file mode 100644 index ca459d07f0..0000000000 --- a/vcx/libvcx/src/error/cred_def.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::fmt; -use error::ToErrorCode; -use utils::error::{NO_PAYMENT_INFORMATION, INVALID_CREDENTIAL_DEF_HANDLE, BUILD_CREDENTIAL_DEF_REQ_ERR, - CREDENTIAL_DEF_ALREADY_CREATED, CREATE_CREDENTIAL_DEF_ERR, INVALID_REVOCATION_DETAILS, - INVALID_REV_REG_DEF_CREATION, INVALID_REV_ENTRY}; - -#[derive(Debug)] -pub enum CredDefError { - BuildCredDefRequestError(), - RetrieveCredDefError(), - CreateCredDefError(), - CredDefAlreadyCreatedError(), - InvalidHandle(), - SchemaError(String), - NoPaymentInformation(), - CommonError(u32), - InvalidRevocationDetails(), - InvalidRevocationEntry(), - CreateRevRegDefError(), -} -impl fmt::Display for CredDefError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CredDefError::SchemaError(ref s) => write!(f, "Schema Error: {}", s), - CredDefError::BuildCredDefRequestError() => write!(f, "Error Building Cred Def Request"), - CredDefError::RetrieveCredDefError() => write!(f, "Error Retrieving Cred Def Request"), - CredDefError::InvalidHandle() => write!(f, "Invalid credentialdef handle"), - CredDefError::CommonError(x) => write!(f, "This Cred Def common error had a value: {}", x), - CredDefError::CreateCredDefError() => write!(f, "{}", CREATE_CREDENTIAL_DEF_ERR.message ), - CredDefError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message ), - CredDefError::CredDefAlreadyCreatedError() => write!(f, "{}", CREDENTIAL_DEF_ALREADY_CREATED.message ), - CredDefError::InvalidRevocationDetails() => write!(f, "{}", INVALID_REVOCATION_DETAILS.message ), - CredDefError::CreateRevRegDefError() => write!(f, "{}", INVALID_REV_REG_DEF_CREATION.message ), - CredDefError::InvalidRevocationEntry() => write!(f, "{}", INVALID_REV_ENTRY.message ), - } - } -} -impl ToErrorCode for CredDefError { - fn to_error_code(&self) -> u32 { - match *self { - CredDefError::SchemaError(ref s) => 7002, - CredDefError::BuildCredDefRequestError() => BUILD_CREDENTIAL_DEF_REQ_ERR.code_num, - CredDefError::RetrieveCredDefError() => 7001, - CredDefError::InvalidHandle() => INVALID_CREDENTIAL_DEF_HANDLE.code_num, - CredDefError::CreateCredDefError() => CREATE_CREDENTIAL_DEF_ERR.code_num, - CredDefError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, - CredDefError::CredDefAlreadyCreatedError() => CREDENTIAL_DEF_ALREADY_CREATED.code_num, - CredDefError::InvalidRevocationDetails() => INVALID_REVOCATION_DETAILS.code_num, - CredDefError::CreateRevRegDefError() => INVALID_REV_REG_DEF_CREATION.code_num, - CredDefError::InvalidRevocationEntry() => INVALID_REV_ENTRY.code_num, - CredDefError::CommonError(x) => x, - } - } -} - -impl PartialEq for CredDefError { - fn eq(&self, other: &CredDefError) -> bool { - self.to_error_code() == other.to_error_code() - } -} \ No newline at end of file diff --git a/vcx/libvcx/src/error/credential.rs b/vcx/libvcx/src/error/credential.rs deleted file mode 100644 index 14b6fa86bd..0000000000 --- a/vcx/libvcx/src/error/credential.rs +++ /dev/null @@ -1,62 +0,0 @@ - -use std::fmt; -use error::ToErrorCode; -use utils::error::{NO_PAYMENT_INFORMATION, INVALID_CREDENTIAL_HANDLE, INVALID_STATE, NOT_READY, INVALID_JSON}; -use error::payment; - -#[derive(Debug)] -pub enum CredentialError { - NotReady(), - InvalidHandle(), - InvalidCredentialJson(), - InvalidState(), - PaymentError(payment::PaymentError), - NoPaymentInformation(), - CommonError(u32), -} - -impl fmt::Display for CredentialError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CredentialError::InvalidState() => write!(f, "{}", INVALID_STATE.message), - CredentialError::NotReady() => write!(f, "{}", NOT_READY.message), - CredentialError::InvalidHandle() => write!(f, "{}", INVALID_CREDENTIAL_HANDLE.message), - CredentialError::InvalidCredentialJson() => write!(f, "{}", INVALID_JSON.message), - CredentialError::PaymentError(ref pe) => write!(f, "Payment Error: {}", pe.to_error_code()), - CredentialError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message), - CredentialError::CommonError(x) => write!(f, "This Credential Error had a value: {}", x), - } - } -} - -impl PartialEq for CredentialError{ - fn eq(&self, other: &CredentialError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -impl ToErrorCode for CredentialError { - fn to_error_code(&self) -> u32 { - match *self { - CredentialError::InvalidState() => INVALID_STATE.code_num, - CredentialError::NotReady() => NOT_READY.code_num, - CredentialError::InvalidHandle() => INVALID_CREDENTIAL_HANDLE.code_num, - CredentialError::InvalidCredentialJson() => INVALID_JSON.code_num, - CredentialError::PaymentError(ref pe) => pe.to_error_code(), - CredentialError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, - CredentialError::CommonError(x) => x, - } - } -} - -impl From for CredentialError { - fn from(error:payment::PaymentError) -> Self { - CredentialError::PaymentError(error) - } -} - -impl From for CredentialError{ - fn from(err: u32) -> Self { - CredentialError::CommonError(err) - } -} \ No newline at end of file diff --git a/vcx/libvcx/src/error/issuer_cred.rs b/vcx/libvcx/src/error/issuer_cred.rs deleted file mode 100644 index be06638c75..0000000000 --- a/vcx/libvcx/src/error/issuer_cred.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::fmt; -use utils::error::{INVALID_REVOCATION_DETAILS, NO_PAYMENT_INFORMATION, OBJECT_CACHE_ERROR, INVALID_CREDENTIAL_JSON, NOT_READY, INVALID_ISSUER_CREDENTIAL_HANDLE, INVALID_CREDENTIAL_REQUEST, INVALID_JSON}; -use error::ToErrorCode; -use serde_json; - -#[derive(Debug)] -pub enum IssuerCredError { - CommonError(u32), - CreateError(), - NotReadyError(), - InvalidHandle(), - InvalidCredRequest(), - InvalidCred(), - NoPaymentInformation(), - InvalidJson(), - InvalidRevocationInfo(), -} - -impl fmt::Display for IssuerCredError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - IssuerCredError::CommonError(x) => write!(f, "This Common Error had value: {}", x), - IssuerCredError::NotReadyError() => write!(f, "{}", NOT_READY.message), - IssuerCredError::InvalidHandle() => write!(f, "{}", INVALID_ISSUER_CREDENTIAL_HANDLE.message), - IssuerCredError::InvalidCredRequest() => write!(f, "{}", INVALID_CREDENTIAL_REQUEST.message), - IssuerCredError::InvalidCred() => write!(f, "{}", INVALID_CREDENTIAL_JSON.message), - IssuerCredError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), - IssuerCredError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message), - IssuerCredError::CreateError() => write!(f, "Could not create issuer credential"), - IssuerCredError::InvalidRevocationInfo() => write!(f, "{}",INVALID_REVOCATION_DETAILS.message), - } - } -} -impl ToErrorCode for IssuerCredError { - fn to_error_code(&self) -> u32 { - match *self { - IssuerCredError::NotReadyError() => NOT_READY.code_num, - IssuerCredError::InvalidHandle() => INVALID_ISSUER_CREDENTIAL_HANDLE.code_num, - IssuerCredError::InvalidCredRequest() => INVALID_CREDENTIAL_REQUEST.code_num, - IssuerCredError::InvalidJson() => INVALID_JSON.code_num, - IssuerCredError::InvalidCred() => INVALID_CREDENTIAL_JSON.code_num, - IssuerCredError::CreateError() => OBJECT_CACHE_ERROR.code_num, - IssuerCredError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, - IssuerCredError::InvalidRevocationInfo() => INVALID_REVOCATION_DETAILS.code_num, - IssuerCredError::CommonError(x) => x, - } - } -} - -impl PartialEq for IssuerCredError { - fn eq(&self, other: &IssuerCredError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -impl From for IssuerCredError { - fn from(err:serde_json::Error) -> Self { - IssuerCredError::InvalidJson() - } -} - -impl From for IssuerCredError{ - fn from(err: u32) -> Self { - IssuerCredError::CommonError(err) - } -} - diff --git a/vcx/libvcx/src/error/messages.rs b/vcx/libvcx/src/error/messages.rs deleted file mode 100644 index 458d703599..0000000000 --- a/vcx/libvcx/src/error/messages.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::fmt; -use error::ToErrorCode; - -#[derive(Debug)] -pub enum MessageError { - MessagePackError(), -} - -impl fmt::Display for MessageError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - MessageError::MessagePackError() => write!(f, "Deserialize Error for Message Pack"), - } - } -} -impl ToErrorCode for MessageError { - fn to_error_code(&self) -> u32 { - match *self { - MessageError::MessagePackError() => 8001, - } - } - -} diff --git a/vcx/libvcx/src/error/mod.rs b/vcx/libvcx/src/error/mod.rs index 71d5c0c77e..b2d7954916 100644 --- a/vcx/libvcx/src/error/mod.rs +++ b/vcx/libvcx/src/error/mod.rs @@ -1,23 +1,423 @@ -pub mod base; -pub mod connection; -pub mod schema; -pub mod cred_def; -pub mod issuer_cred; -pub mod proof; -pub mod credential; -pub mod wallet; -pub mod messages; -pub mod payment; +use std::cell::RefCell; +use std::fmt; +use std::ffi::CString; +use std::ptr; +use failure::{Context, Backtrace, Fail}; +use libc::c_char; -pub trait ToErrorCode { - fn to_error_code(&self) -> u32; +use utils::error; +use utils::cstring::CStringUtils; + +pub mod prelude { + pub use super::{err_msg, VcxError, VcxErrorExt, VcxErrorKind, VcxResult, VcxResultExt, get_current_error_c_json}; +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] +pub enum VcxErrorKind { + // Common + #[fail(display = "Object is in invalid state for requested operation")] + InvalidState, + #[fail(display = "Invalid Configuration")] + InvalidConfiguration, + #[fail(display = "Obj was not found with handle")] + InvalidHandle, + #[fail(display = "Invalid JSON string")] + InvalidJson, + #[fail(display = "Invalid Option")] + InvalidOption, + #[fail(display = "Invalid MessagePack")] + InvalidMessagePack, + #[fail(display = "Object cache error")] + ObjectCacheError, + #[fail(display = "Object not ready for specified action")] + NotReady, + #[fail(display = "IO Error, possibly creating a backup wallet")] + IOError, + #[fail(display = "Object (json, config, key, credential and etc...) passed to libindy has invalid structure")] + LibindyInvalidStructure, + #[fail(display = "Waiting for callback timed out")] + TimeoutLibindy, + #[fail(display = "Parameter passed to libindy was invalid")] + InvalidLibindyParam, + #[fail(display = "Library already initialized")] + AlreadyInitialized, + + // Connection + #[fail(display = "Could not create connection")] + CreateConnection, + #[fail(display = "Invalid Connection Handle")] + InvalidConnectionHandle, + #[fail(display = "Invalid invite details structure")] + InvalidInviteDetail, + #[fail(display = "Cannot Delete Connection. Check status of connection is appropriate to be deleted from agency.")] + DeleteConnection, + #[fail(display = "Error with Connection")] + GeneralConnectionError, + + // Payment + #[fail(display = "No payment information associated with object")] + NoPaymentInformation, + #[fail(display = "Insufficient amount of tokens to process request")] + InsufficientTokenAmount, + #[fail(display = "Invalid payment address")] + InvalidPaymentAddress, + + // Credential Definition error + #[fail(display = "Call to create Credential Definition failed")] + CreateCredDef, + #[fail(display = "Can't create, Credential Def already on ledger")] + CredDefAlreadyCreated, + #[fail(display = "Invalid Credential Definition handle")] + InvalidCredDefHandle, + + // Revocation + #[fail(display = "Failed to create Revocation Registration Definition")] + CreateRevRegDef, + #[fail(display = "Invalid Revocation Details")] + InvalidRevocationDetails, + #[fail(display = "Unable to Update Revocation Delta On Ledger")] + InvalidRevocationEntry, + #[fail(display = "Invalid Credential Revocation timestamp")] + InvalidRevocationTimestamp, + + // Credential + #[fail(display = "Invalid credential handle")] + InvalidCredentialHandle, + #[fail(display = "could not create credential request")] + CreateCredentialRequest, + + // Issuer Credential + #[fail(display = "Invalid Credential Issuer Handle")] + InvalidIssuerCredentialHandle, + #[fail(display = "Invalid Credential Request")] + InvalidCredentialRequest, + #[fail(display = "Invalid credential json")] + InvalidCredential, + #[fail(display = "Attributes provided to Credential Offer are not correct, possibly malformed")] + InvalidAttributesStructure, + + // Proof + #[fail(display = "Invalid proof handle")] + InvalidProofHandle, + #[fail(display = "Obj was not found with handle")] + InvalidDisclosedProofHandle, + #[fail(display = "Proof had invalid format")] + InvalidProof, + #[fail(display = "Schema was invalid or corrupt")] + InvalidSchema, + #[fail(display = "The Proof received does not have valid credentials listed.")] + InvalidProofCredentialData, + #[fail(display = "Could not create proof")] + CreateProof, + #[fail(display = "Proof Request Passed into Libindy Call Was Invalid")] + InvalidProofRequest, + + // Schema + #[fail(display = "Could not create schema")] + CreateSchema, + #[fail(display = "Invalid Schema Handle")] + InvalidSchemaHandle, + #[fail(display = "No Schema for that schema sequence number")] + InvalidSchemaSeqNo, + #[fail(display = "Duplicate Schema: Ledger Already Contains Schema For Given DID, Version, and Name Combination")] + DuplicationSchema, + #[fail(display = "Unknown Rejection of Schema Creation, refer to libindy documentation")] + UnknownSchemaRejection, + + // Pool + #[fail(display = "Formatting for Pool Config are incorrect.")] + CreatePoolConfig, + #[fail(display = "Invalid response from ledger for paid transaction")] + InvalidLedgerResponse, + #[fail(display = "No Pool open. Can't return handle.")] + NoPoolOpen, + #[fail(display = "Message failed in post")] + PostMessageFailed, + + // Wallet + #[fail(display = "Error Creating a wallet")] + WalletCreate, + #[fail(display = "Missing wallet name in config")] + MissingWalletName, + #[fail(display = "Missing exported wallet path in config")] + MissingExportedWalletPath, + #[fail(display = "Missing exported backup key in config")] + MissingBackupKey, + #[fail(display = "Wallet Storage Parameter Either Malformed or Missing")] + InvalidWalletStorageParams, + #[fail(display = "Invalid Wallet or Search Handle")] + InvalidWalletHandle, + #[fail(display = "Indy wallet already exists")] + DuplicationWallet, + #[fail(display = "Wallet record not found")] + WalletRecordNotFound, + #[fail(display = "Record already exists in the wallet")] + DuplicationWalletRecord, + #[fail(display = "Wallet not found")] + WalletNotFound, + #[fail(display = "Indy wallet already open")] + WalletAlreadyOpen, + #[fail(display = "Configuration is missing wallet key")] + MissingWalletKey, + #[fail(display = "Attempted to add a Master Secret that already existed in wallet")] + DuplicationMasterSecret, + #[fail(display = "Attempted to add a DID to wallet when that DID already exists in wallet")] + DuplicationDid, + + // Logger + #[fail(display = "Logging Error")] + LoggingError, + + // Validation + #[fail(display = "Could not encode string to a big integer.")] + EncodeError, + #[fail(display = "Unknown Error")] + UnknownError, + #[fail(display = "Invalid DID")] + InvalidDid, + #[fail(display = "Invalid VERKEY")] + InvalidVerkey, + #[fail(display = "Invalid NONCE")] + InvalidNonce, + #[fail(display = "Invalid URL")] + InvalidUrl, + #[fail(display = "Configuration is missing the Payment Method parameter")] + MissingPaymentMethod, + #[fail(display = "Unable to serialize")] + SerializationError, + #[fail(display = "Value needs to be base58")] + NotBase58, + + // A2A + #[fail(display = "Invalid HTTP response.")] + InvalidHttpResponse, + #[fail(display = "No Endpoint set for Connection Object")] + NoEndpoint, + #[fail(display = "Error Retrieving messages from API")] + InvalidMessages, + + #[fail(display = "Common error {}", 0)] + Common(u32), + #[fail(display = "Liibndy error {}", 0)] + LiibndyError(u32), + #[fail(display = "Unknown libindy error")] + UnknownLiibndyError, +} + +#[derive(Debug)] +pub struct VcxError { + inner: Context +} + +impl Fail for VcxError { + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl fmt::Display for VcxError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut first = true; + + for cause in Fail::iter_chain(&self.inner) { + if first { + first = false; + writeln!(f, "Error: {}", cause)?; + } else { + writeln!(f, " Caused by: {}", cause)?; + } + } + + Ok(()) + } +} + +impl VcxError { + pub fn from_msg(kind: VcxErrorKind, msg: D) -> VcxError + where D: fmt::Display + fmt::Debug + Send + Sync + 'static { + VcxError { inner: Context::new(msg).context(kind) } + } + + pub fn kind(&self) -> VcxErrorKind { + *self.inner.get_context() + } + + pub fn extend(self, msg: D) -> VcxError + where D: fmt::Display + fmt::Debug + Send + Sync + 'static { + let kind = self.kind(); + VcxError { inner: self.inner.map(|_| msg).context(kind) } + } + + pub fn map(self, kind: VcxErrorKind, msg: D) -> VcxError + where D: fmt::Display + fmt::Debug + Send + Sync + 'static { + VcxError { inner: self.inner.map(|_| msg).context(kind) } + } } -#[cfg(test)] -mod tests { - #[test] - fn test_to_error_code(){ +pub fn err_msg(kind: VcxErrorKind, msg: D) -> VcxError + where D: fmt::Display + fmt::Debug + Send + Sync + 'static { + VcxError::from_msg(kind, msg) +} + +impl From for VcxError { + fn from(kind: VcxErrorKind) -> VcxError { + VcxError::from_msg(kind, ::utils::error::error_message(&kind.clone().into())) + } +} +impl From> for VcxError { + fn from(inner: Context) -> VcxError { + VcxError { inner } } } + +impl From for u32 { + fn from(code: VcxError) -> u32 { + set_current_error(&code); + code.kind().into() + } +} + +impl From for u32 { + fn from(code: VcxErrorKind) -> u32 { + match code { + VcxErrorKind::InvalidState => error::INVALID_STATE.code_num, + VcxErrorKind::InvalidConfiguration => error::INVALID_CONFIGURATION.code_num, + VcxErrorKind::InvalidHandle => error::INVALID_OBJ_HANDLE.code_num, + VcxErrorKind::InvalidJson => error::INVALID_JSON.code_num, + VcxErrorKind::InvalidOption => error::INVALID_OPTION.code_num, + VcxErrorKind::InvalidMessagePack => error::INVALID_MSGPACK.code_num, + VcxErrorKind::ObjectCacheError => error::OBJECT_CACHE_ERROR.code_num, + VcxErrorKind::NoPaymentInformation => error::NO_PAYMENT_INFORMATION.code_num, + VcxErrorKind::NotReady => error::NOT_READY.code_num, + VcxErrorKind::InvalidRevocationDetails => error::INVALID_REVOCATION_DETAILS.code_num, + VcxErrorKind::GeneralConnectionError => error::CONNECTION_ERROR.code_num, + VcxErrorKind::IOError => error::IOERROR.code_num, + VcxErrorKind::LibindyInvalidStructure => error::LIBINDY_INVALID_STRUCTURE.code_num, + VcxErrorKind::TimeoutLibindy => error::TIMEOUT_LIBINDY_ERROR.code_num, + VcxErrorKind::InvalidLibindyParam => error::INVALID_LIBINDY_PARAM.code_num, + VcxErrorKind::AlreadyInitialized => error::ALREADY_INITIALIZED.code_num, + VcxErrorKind::CreateConnection => error::CREATE_CONNECTION_ERROR.code_num, + VcxErrorKind::InvalidConnectionHandle => error::INVALID_CONNECTION_HANDLE.code_num, + VcxErrorKind::InvalidInviteDetail => error::INVALID_INVITE_DETAILS.code_num, + VcxErrorKind::DeleteConnection => error::CANNOT_DELETE_CONNECTION.code_num, + VcxErrorKind::CreateCredDef => error::CREATE_CREDENTIAL_DEF_ERR.code_num, + VcxErrorKind::CredDefAlreadyCreated => error::CREDENTIAL_DEF_ALREADY_CREATED.code_num, + VcxErrorKind::InvalidCredDefHandle => error::INVALID_CREDENTIAL_DEF_HANDLE.code_num, + VcxErrorKind::InvalidRevocationEntry => error::INVALID_REV_ENTRY.code_num, + VcxErrorKind::CreateRevRegDef => error::INVALID_REV_REG_DEF_CREATION.code_num, + VcxErrorKind::InvalidCredentialHandle => error::INVALID_CREDENTIAL_HANDLE.code_num, + VcxErrorKind::CreateCredentialRequest => error::CREATE_CREDENTIAL_REQUEST_ERROR.code_num, + VcxErrorKind::InvalidIssuerCredentialHandle => error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num, + VcxErrorKind::InvalidCredentialRequest => error::INVALID_CREDENTIAL_REQUEST.code_num, + VcxErrorKind::InvalidCredential => error::INVALID_CREDENTIAL_JSON.code_num, + VcxErrorKind::InsufficientTokenAmount => error::INSUFFICIENT_TOKEN_AMOUNT.code_num, + VcxErrorKind::InvalidProofHandle => error::INVALID_PROOF_HANDLE.code_num, + VcxErrorKind::InvalidDisclosedProofHandle => error::INVALID_DISCLOSED_PROOF_HANDLE.code_num, + VcxErrorKind::InvalidProof => error::INVALID_PROOF.code_num, + VcxErrorKind::InvalidSchema => error::INVALID_SCHEMA.code_num, + VcxErrorKind::InvalidProofCredentialData => error::INVALID_PROOF_CREDENTIAL_DATA.code_num, + VcxErrorKind::CreateProof => error::CREATE_PROOF_ERROR.code_num, + VcxErrorKind::InvalidRevocationTimestamp => error::INVALID_REVOCATION_TIMESTAMP.code_num, + VcxErrorKind::CreateSchema => error::INVALID_SCHEMA_CREATION.code_num, + VcxErrorKind::InvalidSchemaHandle => error::INVALID_SCHEMA_HANDLE.code_num, + VcxErrorKind::InvalidSchemaSeqNo => error::INVALID_SCHEMA_SEQ_NO.code_num, + VcxErrorKind::DuplicationSchema => error::DUPLICATE_SCHEMA.code_num, + VcxErrorKind::UnknownSchemaRejection => error::UNKNOWN_SCHEMA_REJECTION.code_num, + VcxErrorKind::WalletCreate => error::INVALID_WALLET_CREATION.code_num, + VcxErrorKind::MissingWalletName => error::MISSING_WALLET_NAME.code_num, + VcxErrorKind::InvalidWalletStorageParams => error::INVALID_WALLET_STORAGE_PARAMETER.code_num, + VcxErrorKind::InvalidWalletHandle => error::INVALID_WALLET_HANDLE.code_num, + VcxErrorKind::DuplicationWallet => error::WALLET_ALREADY_EXISTS.code_num, + VcxErrorKind::WalletNotFound => error::WALLET_NOT_FOUND.code_num, + VcxErrorKind::WalletRecordNotFound => error::WALLET_RECORD_NOT_FOUND.code_num, + VcxErrorKind::CreatePoolConfig => error::CREATE_POOL_CONFIG.code_num, + VcxErrorKind::DuplicationWalletRecord => error::DUPLICATE_WALLET_RECORD.code_num, + VcxErrorKind::WalletAlreadyOpen => error::WALLET_ALREADY_OPEN.code_num, + VcxErrorKind::DuplicationMasterSecret => error::DUPLICATE_MASTER_SECRET.code_num, + VcxErrorKind::DuplicationDid => error::DID_ALREADY_EXISTS_IN_WALLET.code_num, + VcxErrorKind::InvalidLedgerResponse => error::INVALID_LEDGER_RESPONSE.code_num, + VcxErrorKind::InvalidAttributesStructure => error::INVALID_ATTRIBUTES_STRUCTURE.code_num, + VcxErrorKind::InvalidPaymentAddress => error::INVALID_PAYMENT_ADDRESS.code_num, + VcxErrorKind::NoEndpoint => error::NO_ENDPOINT.code_num, + VcxErrorKind::InvalidProofRequest => error::INVALID_PROOF_REQUEST.code_num, + VcxErrorKind::NoPoolOpen => error::NO_POOL_OPEN.code_num, + VcxErrorKind::PostMessageFailed => error::POST_MSG_FAILURE.code_num, + VcxErrorKind::LoggingError => error::LOGGING_ERROR.code_num, + VcxErrorKind::EncodeError => error::BIG_NUMBER_ERROR.code_num, + VcxErrorKind::UnknownError => error::UNKNOWN_ERROR.code_num, + VcxErrorKind::InvalidDid => error::INVALID_DID.code_num, + VcxErrorKind::InvalidVerkey => error::INVALID_VERKEY.code_num, + VcxErrorKind::InvalidNonce => error::INVALID_NONCE.code_num, + VcxErrorKind::InvalidUrl => error::INVALID_URL.code_num, + VcxErrorKind::MissingWalletKey => error::MISSING_WALLET_KEY.code_num, + VcxErrorKind::MissingPaymentMethod => error::MISSING_PAYMENT_METHOD.code_num, + VcxErrorKind::SerializationError => error::SERIALIZATION_ERROR.code_num, + VcxErrorKind::NotBase58 => error::NOT_BASE58.code_num, + VcxErrorKind::InvalidHttpResponse => error::INVALID_HTTP_RESPONSE.code_num, + VcxErrorKind::InvalidMessages => error::INVALID_MESSAGES.code_num, + VcxErrorKind::MissingExportedWalletPath => error::MISSING_EXPORTED_WALLET_PATH.code_num, + VcxErrorKind::MissingBackupKey => error::MISSING_BACKUP_KEY.code_num, + VcxErrorKind::UnknownLiibndyError => error::UNKNOWN_LIBINDY_ERROR.code_num, + VcxErrorKind::Common(num) => num, + VcxErrorKind::LiibndyError(num) => num, + } + } +} + +pub type VcxResult = Result; + +/// Extension methods for `Result`. +pub trait VcxResultExt { + fn to_vcx(self, kind: VcxErrorKind, msg: D) -> VcxResult where D: fmt::Display + Send + Sync + 'static; +} + +impl VcxResultExt for Result where E: Fail +{ + fn to_vcx(self, kind: VcxErrorKind, msg: D) -> VcxResult where D: fmt::Display + Send + Sync + 'static { + self.map_err(|err| err.context(msg).context(kind).into()) + } +} + +/// Extension methods for `Error`. +pub trait VcxErrorExt { + fn to_vcx(self, kind: VcxErrorKind, msg: D) -> VcxError where D: fmt::Display + Send + Sync + 'static; +} + +impl VcxErrorExt for E where E: Fail +{ + fn to_vcx(self, kind: VcxErrorKind, msg: D) -> VcxError where D: fmt::Display + Send + Sync + 'static { + self.context(msg).context(kind).into() + } +} + +thread_local! { + pub static CURRENT_ERROR_C_JSON: RefCell> = RefCell::new(None); +} + +pub fn set_current_error(err: &VcxError) { + CURRENT_ERROR_C_JSON.with(|error| { + let error_json = json!({ + "error": err.kind().to_string(), + "message": err.to_string(), + "cause": Fail::find_root_cause(err).to_string(), + "backtrace": err.backtrace().map(|bt| bt.to_string()) + }).to_string(); + error.replace(Some(CStringUtils::string_to_cstring(error_json))); + }); +} + +pub fn get_current_error_c_json() -> *const c_char { + let mut value = ptr::null(); + + CURRENT_ERROR_C_JSON.with(|err| + err.borrow().as_ref().map(|err| value = err.as_ptr()) + ); + + value +} \ No newline at end of file diff --git a/vcx/libvcx/src/error/payment.rs b/vcx/libvcx/src/error/payment.rs deleted file mode 100644 index 519e5f0677..0000000000 --- a/vcx/libvcx/src/error/payment.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::error::Error; -use error::ToErrorCode; -use utils::error:: { INVALID_OBJ_HANDLE, INSUFFICIENT_TOKEN_AMOUNT, INVALID_JSON }; -use std::fmt; - -#[derive(Debug)] -pub enum PaymentError { - InvalidHandle(), - InsufficientFunds(), - InvalidWalletJson(), - CommonError(u32), -} - -impl fmt::Display for PaymentError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt:: Result { - match *self { - PaymentError::InvalidHandle() => write!(f, "{}", INVALID_OBJ_HANDLE.message), - PaymentError::InsufficientFunds() => write!(f, "{}", INSUFFICIENT_TOKEN_AMOUNT.message), - PaymentError::InvalidWalletJson() => write!(f, "{}", INVALID_JSON.message), - PaymentError::CommonError(ec) => write!( f, "Libindy/Commmon Error: {}", ec), - } - } -} -impl Error for PaymentError { - fn cause(&self) -> Option<&Error> { - match *self { - PaymentError::InvalidHandle() => None, - PaymentError::InsufficientFunds() => None, - PaymentError::InvalidWalletJson() => None, - PaymentError::CommonError(ec) => None, - } - } - - fn description(&self) -> &str { - match *self { - PaymentError::InvalidHandle() => INVALID_OBJ_HANDLE.message, - PaymentError::InsufficientFunds() => INSUFFICIENT_TOKEN_AMOUNT.message, - PaymentError::InvalidWalletJson() => INVALID_JSON.message, - PaymentError::CommonError(ec) => "Libindy/Common Error", - } - } -} - -impl ToErrorCode for PaymentError { - fn to_error_code(&self) -> u32 { - match *self { - PaymentError::InvalidHandle() => INVALID_OBJ_HANDLE.code_num, - PaymentError::InsufficientFunds() => INSUFFICIENT_TOKEN_AMOUNT.code_num, - PaymentError::InvalidWalletJson() => INVALID_JSON.code_num, - PaymentError::CommonError(ec) => ec, - } - } -} - -impl PartialEq for PaymentError { - fn eq(&self, other: &PaymentError) -> bool {self.to_error_code() == other.to_error_code() } -} - diff --git a/vcx/libvcx/src/error/proof.rs b/vcx/libvcx/src/error/proof.rs deleted file mode 100644 index 9456253784..0000000000 --- a/vcx/libvcx/src/error/proof.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::fmt; -use error::ToErrorCode; -use utils::error::{INVALID_JSON, INVALID_PROOF_HANDLE, INVALID_PROOF, INVALID_PROOF_CREDENTIAL_DATA, INVALID_SCHEMA, -NOT_READY, INVALID_CONNECTION_HANDLE, CONNECTION_ERROR, FAILED_PROOF_COMPLIANCE, CREATE_PROOF_ERROR, INVALID_REVOCATION_TIMESTAMP, INVALID_REVOCATION_DETAILS}; - - -#[derive(Debug)] -pub enum ProofError{ - InvalidHandle(), - InvalidProof(), - InvalidCredData(), - InvalidSchema(), - InvalidRevocationInfo(), - ProofNotReadyError(), - ProofMessageError(u32), - ProofConnectionError(), - CreateProofError(), - InvalidConnection(), - FailedProofCompliance(), - InvalidJson(), - InvalidTimestamp(), - CommonError(u32), -} - -impl fmt::Display for ProofError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ProofError::InvalidHandle() => write!(f, "{}", INVALID_PROOF_HANDLE.message), - ProofError::InvalidProof() => write!(f, "{}", INVALID_PROOF.message), - ProofError::InvalidSchema() => write!(f, "{}", INVALID_SCHEMA.message), - ProofError::InvalidCredData() => write!(f, "{}", INVALID_PROOF_CREDENTIAL_DATA.message), - ProofError::InvalidConnection() => write!(f, "{}", CONNECTION_ERROR.message), - ProofError::ProofNotReadyError() => write!(f, "{}", NOT_READY.message), - ProofError::ProofConnectionError() => write!(f, "{}", INVALID_CONNECTION_HANDLE.message), - ProofError::FailedProofCompliance() => write!(f, "{}", FAILED_PROOF_COMPLIANCE.message), - ProofError::CreateProofError() => write!(f, "{}", CREATE_PROOF_ERROR.message), - ProofError::ProofMessageError(x) => write!(f, "Proof Error: Message Error value: , {}", x), - ProofError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), - ProofError::InvalidTimestamp() => write!(f, "{}", INVALID_REVOCATION_TIMESTAMP.message), - ProofError::InvalidRevocationInfo() => write!(f, "{}",INVALID_REVOCATION_DETAILS.message), - ProofError::CommonError(x) => write!(f, "This Proof Error Common Error had value: {}", x), - } - } -} - -impl PartialEq for ProofError { - fn eq(&self, other: &ProofError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -impl ToErrorCode for ProofError { - fn to_error_code(&self) -> u32 { - match *self { - ProofError::InvalidHandle() => INVALID_PROOF_HANDLE.code_num, - ProofError::InvalidProof() => INVALID_PROOF.code_num, - ProofError::InvalidSchema() => INVALID_SCHEMA.code_num, - ProofError::InvalidCredData() => INVALID_PROOF_CREDENTIAL_DATA.code_num, - ProofError::InvalidRevocationInfo() => INVALID_REVOCATION_DETAILS.code_num, - ProofError::InvalidConnection() => CONNECTION_ERROR.code_num, - ProofError::CreateProofError() => CREATE_PROOF_ERROR.code_num, - ProofError::ProofNotReadyError() => NOT_READY.code_num, - ProofError::ProofConnectionError() => INVALID_CONNECTION_HANDLE.code_num, - ProofError::FailedProofCompliance() => FAILED_PROOF_COMPLIANCE.code_num, - ProofError::InvalidJson() => INVALID_JSON.code_num, - ProofError::InvalidTimestamp() => INVALID_REVOCATION_TIMESTAMP.code_num, - ProofError::ProofMessageError(x) => x, - ProofError::CommonError(x) => x, - } - } -} - -impl From for ProofError{ - fn from(err: u32) -> Self { - ProofError::CommonError(err) - } -} - diff --git a/vcx/libvcx/src/error/schema.rs b/vcx/libvcx/src/error/schema.rs deleted file mode 100644 index b9ff8b073a..0000000000 --- a/vcx/libvcx/src/error/schema.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::fmt; -use error::ToErrorCode; -use utils::error::{NO_PAYMENT_INFORMATION, INVALID_SCHEMA_CREATION, INVALID_SCHEMA_HANDLE, INVALID_SCHEMA_SEQ_NO, DUPLICATE_SCHEMA, UNKNOWN_SCHEMA_REJECTION}; -#[derive(Debug)] -pub enum SchemaError { - InvalidSchemaCreation(), - InvalidHandle(), - InvalidSchemaSeqNo(), - DuplicateSchema(), - UnknownRejection(), - NoPaymentInformation(), - CommonError(u32), -} - -impl ToErrorCode for SchemaError { - fn to_error_code(&self) -> u32 { - match *self { - SchemaError::InvalidSchemaCreation() => INVALID_SCHEMA_CREATION.code_num, - SchemaError::InvalidHandle() => INVALID_SCHEMA_HANDLE.code_num, - SchemaError::InvalidSchemaSeqNo() => INVALID_SCHEMA_SEQ_NO.code_num, - SchemaError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, - SchemaError::UnknownRejection() => UNKNOWN_SCHEMA_REJECTION.code_num, - SchemaError::DuplicateSchema() => DUPLICATE_SCHEMA.code_num, - SchemaError::CommonError(x) => x, - } - } -} - -impl fmt::Display for SchemaError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - SchemaError::InvalidSchemaCreation() => write!(f, "{}", INVALID_SCHEMA_CREATION.message), - SchemaError::InvalidHandle() => write!(f, "{}", INVALID_SCHEMA_HANDLE.message), - SchemaError::InvalidSchemaSeqNo() => write!(f, "{}", INVALID_SCHEMA_SEQ_NO.message), - SchemaError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message), - SchemaError::UnknownRejection() => write!(f, "{}", UNKNOWN_SCHEMA_REJECTION.code_num), - SchemaError::DuplicateSchema() => write!(f, "{}", DUPLICATE_SCHEMA.message), - SchemaError::CommonError(x) => write!(f, "This Schema Common Error had a value of {}", x), - } - } -} - -impl PartialEq for SchemaError { - fn eq(&self, other: &SchemaError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_schema_error () { - assert_eq!(SchemaError::InvalidSchemaCreation().to_error_code(), INVALID_SCHEMA_CREATION.code_num); - } - -} \ No newline at end of file diff --git a/vcx/libvcx/src/error/wallet.rs b/vcx/libvcx/src/error/wallet.rs deleted file mode 100644 index 307797d8ef..0000000000 --- a/vcx/libvcx/src/error/wallet.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::fmt; -use error::ToErrorCode; -use utils::error::{ - INVALID_WALLET_CREATION, - INVALID_WALLET_HANDLE, - WALLET_ALREADY_EXISTS, - INVALID_JSON, - IOERROR, - WALLET_RECORD_NOT_FOUND, - INVALID_WALLET_STORAGE_PARAMETER, -}; - -#[derive(Debug)] -pub enum WalletError { - InvalidWalletCreation(), - InvalidParamters(), - InvalidHandle(), - InvalidJson(), - IoError(), - DuplicateWallet(String), - RecordNotFound(), - CommonError(u32), -} - -impl ToErrorCode for WalletError { - fn to_error_code(&self) -> u32 { - match *self { - WalletError::InvalidWalletCreation() => INVALID_WALLET_CREATION.code_num, - WalletError::InvalidHandle() => INVALID_WALLET_HANDLE.code_num, - WalletError::DuplicateWallet(_) => WALLET_ALREADY_EXISTS.code_num, - WalletError::InvalidJson() => INVALID_JSON.code_num, - WalletError::IoError() => IOERROR.code_num, - WalletError::InvalidParamters() => INVALID_WALLET_STORAGE_PARAMETER.code_num, - WalletError::RecordNotFound() => WALLET_RECORD_NOT_FOUND.code_num, - WalletError::CommonError(x) => x, - } - } -} - -impl fmt::Display for WalletError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - WalletError::InvalidWalletCreation() => write!(f, "{}", INVALID_WALLET_CREATION.message), - WalletError::InvalidHandle() => write!(f, "{}", INVALID_WALLET_HANDLE.message), - WalletError::IoError() => write!(f, "{}", IOERROR.message), - WalletError::DuplicateWallet(ref s) => write!(f, "{}", s), - WalletError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), - WalletError::InvalidParamters() => write!(f, "{}", INVALID_WALLET_STORAGE_PARAMETER.message), - WalletError::RecordNotFound() => write!(f, "{}", WALLET_RECORD_NOT_FOUND.message), - WalletError::CommonError(x) => write!(f, "This Wallet Common Error had a value of {}", x), - } - } -} - -impl PartialEq for WalletError { - fn eq(&self, other: &WalletError) -> bool { - self.to_error_code() == other.to_error_code() - } -} - -impl From for WalletError { - fn from(ec: u32) -> WalletError { - match ec { - 114 => WalletError::IoError(), - 200 => WalletError::InvalidWalletCreation(), - 1067 => WalletError::InvalidParamters(), - e => WalletError::CommonError(e), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_wallet_err () { - assert_eq!(WalletError::InvalidHandle().to_error_code(), INVALID_WALLET_HANDLE.code_num); - } - -} diff --git a/vcx/libvcx/src/issuer_credential.rs b/vcx/libvcx/src/issuer_credential.rs index d3ad449b2b..2fe93c7f26 100644 --- a/vcx/libvcx/src/issuer_credential.rs +++ b/vcx/libvcx/src/issuer_credential.rs @@ -1,34 +1,28 @@ -extern crate rand; -extern crate serde_json; -extern crate libc; +use serde_json; use std::collections::HashMap; use api::VcxStateType; use messages; use settings; -use messages::{RemoteMessageType, MessageStatusCode, GeneralMessage}; +use messages::{RemoteMessageType, MessageStatusCode, GeneralMessage, ObjectWithVersion}; use messages::payload::{Payloads, PayloadKinds, Thread}; use connection; use credential_request::CredentialRequest; use utils::error; -use utils::error::INVALID_JSON; -use utils::libindy::payments; -use utils::libindy::anoncreds; -use utils::constants::CRED_MSG; +use utils::libindy::{payments, anoncreds}; +use utils::constants::{CRED_MSG, DEFAULT_SERIALIZE_VERSION}; use utils::openssl::encode; use utils::libindy::payments::PaymentTxn; -use error::{issuer_cred::IssuerCredError, ToErrorCode, payment::PaymentError}; -use utils::constants::DEFAULT_SERIALIZE_VERSION; -use serde_json::Value; use object_cache::ObjectCache; +use error::prelude::*; lazy_static! { -static ref ISSUER_CREDENTIAL_MAP: ObjectCache < IssuerCredential > = Default::default(); + static ref ISSUER_CREDENTIAL_MAP: ObjectCache < IssuerCredential > = Default::default(); } static CREDENTIAL_OFFER_ID_KEY: &str = "claim_offer_id"; -#[derive(Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct IssuerCredential { source_id: String, credential_attributes: String, @@ -111,50 +105,54 @@ pub struct PaymentInfo { } impl PaymentInfo { - pub fn get_address(&self) -> Result { - Ok(self.payment_addr.to_string()) + pub fn get_address(&self) -> String { + self.payment_addr.to_string() } - pub fn get_price(&self) -> Result { - Ok(self.price) + pub fn get_price(&self) -> u64 { + self.price } - pub fn to_string(&self) -> Result { serde_json::to_string(&self).or(Err(PaymentError::InvalidWalletJson())) } + pub fn to_string(&self) -> VcxResult { + serde_json::to_string(&self) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payment info"))) + } } impl IssuerCredential { - fn validate_credential_offer(&self) -> Result { + fn validate_credential_offer(&self) -> VcxResult { //TODO: validate credential_attributes against credential_def debug!("successfully validated issuer_credential {}", self.source_id); Ok(error::SUCCESS.code_num) } - fn send_credential_offer(&mut self, connection_handle: u32) -> Result { + fn send_credential_offer(&mut self, connection_handle: u32) -> VcxResult { trace!("IssuerCredential::send_credential_offer >>> connection_handle: {}", connection_handle); debug!("sending credential offer for issuer_credential {} to connection {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); if self.state != VcxStateType::VcxStateInitialized { warn!("credential {} has invalid state {} for sending credentialOffer", self.source_id, self.state as u32); - return Err(IssuerCredError::NotReadyError()); + return Err(VcxError::from_msg(VcxErrorKind::NotReady, format!("credential {} has invalid state {} for sending credentialOffer", self.source_id, self.state as u32))); } - if connection::is_valid_handle(connection_handle) == false { + if !connection::is_valid_handle(connection_handle) { warn!("invalid connection handle ({})", connection_handle); - return Err(IssuerCredError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num)); + return Err(VcxError::from_msg(VcxErrorKind::InvalidConnectionHandle, format!("invalid connection handle ({})", connection_handle))); } - self.agent_did = connection::get_agent_did(connection_handle).map_err(|e| IssuerCredError::CommonError(e.to_error_code()))?; - self.agent_vk = connection::get_agent_verkey(connection_handle).map_err(|e| IssuerCredError::CommonError(e.to_error_code()))?; - self.issued_did = connection::get_pw_did(connection_handle).map_err(|x| IssuerCredError::CommonError(x.to_error_code()))?; - self.issued_vk = connection::get_pw_verkey(connection_handle).map_err(|x| IssuerCredError::CommonError(x.to_error_code()))?; - self.remote_vk = connection::get_their_pw_verkey(connection_handle).map_err(|x| IssuerCredError::CommonError(x.to_error_code()))?; + self.agent_did = connection::get_agent_did(connection_handle)?; + self.agent_vk = connection::get_agent_verkey(connection_handle)?; + self.issued_did = connection::get_pw_did(connection_handle)?; + self.issued_vk = connection::get_pw_verkey(connection_handle)?; + self.remote_vk = connection::get_their_pw_verkey(connection_handle)?; let payment = self.generate_payment_info()?; let credential_offer = self.generate_credential_offer(&self.issued_did)?; let cred_json = json!(credential_offer); let mut payload = Vec::new(); - let connection_name = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME).map_err(|e| IssuerCredError::CommonError(e))?; + let connection_name = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME)?; + let title = if let Some(x) = payment { payload.push(json!(x)); format!("{} wants you to pay tokens for: {}", connection_name, self.credential_name) @@ -164,7 +162,8 @@ impl IssuerCredential { payload.push(cred_json); - let payload = serde_json::to_string(&payload).or(Err(IssuerCredError::CommonError(error::INVALID_JSON.code_num)))?; + let payload = serde_json::to_string(&payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize payload: {}", err)))?; debug!("credential offer data: {}", payload); @@ -180,10 +179,7 @@ impl IssuerCredential { .set_detail(&title)? .status_code(&MessageStatusCode::Accepted)? .send_secure() - .map_err(|err| { - warn!("could not send credentialOffer: {}", err); - err - })?; + .map_err(|err| err.extend("could not send credential offer"))?; self.msg_uid = response.get_msg_uid()?; self.state = VcxStateType::VcxStateOfferSent; @@ -193,33 +189,39 @@ impl IssuerCredential { return Ok(error::SUCCESS.code_num); } - fn send_credential(&mut self, connection_handle: u32) -> Result { + fn send_credential(&mut self, connection_handle: u32) -> VcxResult { trace!("IssuerCredential::send_credential >>> connection_handle: {}", connection_handle); debug!("sending credential for issuer_credential {} to connection {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); if self.state != VcxStateType::VcxStateRequestReceived { warn!("credential {} has invalid state {} for sending credential", self.source_id, self.state as u32); - return Err(IssuerCredError::NotReadyError()); + return Err(VcxError::from_msg(VcxErrorKind::NotReady, format!("credential {} has invalid state {} for sending credential", self.source_id, self.state as u32))); } if connection::is_valid_handle(connection_handle) == false { warn!("invalid connection handle ({}) in send_credential_offer", connection_handle); - return Err(IssuerCredError::InvalidHandle()); + return Err(VcxError::from_msg(VcxErrorKind::InvalidCredentialHandle, format!("invalid connection handle ({}) in send_credential_offer", connection_handle))); } - self.verify_payment().map_err(|e| IssuerCredError::CommonError(e))?; + self.verify_payment()?; - let to = connection::get_pw_did(connection_handle).map_err(|e| IssuerCredError::CommonError(e.to_error_code()))?; + let to = connection::get_pw_did(connection_handle)?; let attrs_with_encodings = self.create_attributes_encodings()?; - let data = if settings::test_indy_mode_enabled() { CRED_MSG.to_string() } else { + + let data = if settings::test_indy_mode_enabled() { + CRED_MSG.to_string() + } else { let cred = self.generate_credential(&attrs_with_encodings, &to)?; - serde_json::to_string(&cred).or(Err(IssuerCredError::InvalidCred()))? + serde_json::to_string(&cred) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidCredential, format!("Cannot serialize credential: {}", err)))? }; debug!("credential data: {}", data); - let cred_req_msg_id = self.credential_request.as_ref().and_then(|cred_req| cred_req.msg_ref_id.as_ref()) - .ok_or(IssuerCredError::InvalidCredRequest())?; + let cred_req_msg_id = self.credential_request + .as_ref() + .and_then(|cred_req| cred_req.msg_ref_id.as_ref()) + .ok_or(VcxError::from(VcxErrorKind::InvalidCredentialRequest))?; self.thread.as_mut().map(|thread| thread.sender_order += 1); @@ -233,10 +235,7 @@ impl IssuerCredential { .agent_vk(&self.agent_vk)? .ref_msg_id(cred_req_msg_id)? .send_secure() - .map_err(|err| { - warn!("could not send credential: {}", err); - err - })?; + .map_err(|err| err.extend("could not send credential offer"))?; self.msg_uid = response.get_msg_uid()?; self.state = VcxStateType::VcxStateAccepted; @@ -245,13 +244,13 @@ impl IssuerCredential { return Ok(error::SUCCESS.code_num); } - pub fn create_attributes_encodings(&self) -> Result { + pub fn create_attributes_encodings(&self) -> VcxResult { encode_attributes(&self.credential_attributes) } // TODO: The error arm of this Result is never used in any calling functions. // So currently there is no way to test the error status. - fn get_credential_offer_status(&mut self) -> Result { + fn get_credential_offer_status(&mut self) -> VcxResult { debug!("updating state for credential offer: {} msg_uid: {:?}", self.source_id, self.msg_uid); if self.state == VcxStateType::VcxStateRequestReceived { return Ok(self.get_state()); @@ -263,11 +262,15 @@ impl IssuerCredential { &self.issued_did, &self.issued_vk, &self.agent_did, - &self.agent_vk) - .map_err(|wc| IssuerCredError::CommonError(wc))?; + &self.agent_vk)?; + + let (payload, thread) = Payloads::decrypt(&self.issued_vk, &payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::Common(err.into()), "Cannot decrypt CredentialOffer payload"))?; - let (payload, thread) = Payloads::decrypt(&self.issued_vk, &payload).map_err(|ec| IssuerCredError::CommonError(ec))?; - let cred_req = parse_credential_req_payload(offer_uid, payload)?; + let mut cred_req: CredentialRequest = serde_json::from_str(&payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize CredentialRequest: {}", err)))?; + + cred_req.msg_ref_id = Some(offer_uid); if let Some(tr) = thread { let remote_did = self.remote_did.as_str(); @@ -280,7 +283,7 @@ impl IssuerCredential { Ok(self.get_state()) } - fn update_state(&mut self) -> Result { + fn update_state(&mut self) -> VcxResult { trace!("IssuerCredential::update_state >>>"); self.get_credential_offer_status() //There will probably be more things here once we do other things with the credential @@ -293,28 +296,25 @@ impl IssuerCredential { } fn get_offer_uid(&self) -> &String { &self.msg_uid } fn set_offer_uid(&mut self, uid: &str) { self.msg_uid = uid.to_owned(); } - fn set_credential_request(&mut self, credential_request: CredentialRequest) -> Result { - self.credential_request = Some(credential_request); - Ok(error::SUCCESS.code_num) - } fn get_credential_attributes(&self) -> &String { &self.credential_attributes } fn get_source_id(&self) -> &String { &self.source_id } - fn generate_credential(&mut self, credential_data: &str, did: &str) -> Result { - let indy_cred_offer = &self.credential_offer.as_ref() - .ok_or(IssuerCredError::InvalidCred())?.libindy_offer; + fn generate_credential(&mut self, credential_data: &str, did: &str) -> VcxResult { + let indy_cred_offer = self.credential_offer + .as_ref() + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidCredential, "Invalid Credential: `credential_offer` field not found"))?; - let indy_cred_req = &self.credential_request.as_ref() - .ok_or(IssuerCredError::InvalidCredRequest())?.libindy_cred_req; + let indy_cred_req = self.credential_request + .as_ref() + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidCredentialRequest, "Invalid Credential: `credential_request` field not found"))?; - let (cred, cred_revoc_id, revoc_reg_delta_json) = anoncreds::libindy_issuer_create_credential( - &indy_cred_offer, - &indy_cred_req, - credential_data, - self.rev_reg_id.clone(), - self.tails_file.clone()) - .map_err(|x| IssuerCredError::CommonError(x))?; + let (cred, cred_revoc_id, revoc_reg_delta_json) = + anoncreds::libindy_issuer_create_credential(&indy_cred_offer.libindy_offer, + &indy_cred_req.libindy_cred_req, + &credential_data, + self.rev_reg_id.clone(), + self.tails_file.clone())?; self.cred_rev_id = cred_revoc_id.clone(); @@ -331,11 +331,11 @@ impl IssuerCredential { }) } - fn generate_credential_offer(&self, to_did: &str) -> Result { + fn generate_credential_offer(&self, to_did: &str) -> VcxResult { let attr_map = convert_to_map(&self.credential_attributes)?; //Todo: make a cred_def_offer error - let libindy_offer = anoncreds::libindy_issuer_create_credential_offer(&self.cred_def_id) - .map_err(|err| IssuerCredError::CommonError(err))?; + let libindy_offer = anoncreds::libindy_issuer_create_credential_offer(&self.cred_def_id)?; + Ok(CredentialOffer { msg_type: PayloadKinds::CredOffer.name().to_string(), version: String::from("0.1"), @@ -352,29 +352,28 @@ impl IssuerCredential { }) } - fn revoke_cred(&mut self) -> Result<(), IssuerCredError> { + fn revoke_cred(&mut self) -> VcxResult<()> { let tails_file = self.tails_file .as_ref() - .ok_or(IssuerCredError::InvalidRevocationInfo())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Invalid RevocationInfo: `tails_file` field not found"))?; let rev_reg_id = self.rev_reg_id .as_ref() - .ok_or(IssuerCredError::InvalidRevocationInfo())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Invalid RevocationInfo: `rev_reg_id` field not found"))?; let cred_rev_id = self.cred_rev_id .as_ref() - .ok_or(IssuerCredError::InvalidRevocationInfo())?; + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Invalid RevocationInfo: `cred_rev_id` field not found"))?; - let (payment, _) = anoncreds::revoke_credential(tails_file, rev_reg_id, cred_rev_id) - .map_err(|e| IssuerCredError::CommonError(e))?; + let (payment, _) = anoncreds::revoke_credential(tails_file, rev_reg_id, cred_rev_id)?; self.rev_cred_payment_txn = payment; Ok(()) } - fn generate_payment_info(&mut self) -> Result, IssuerCredError> { + fn generate_payment_info(&mut self) -> VcxResult> { if self.price > 0 { - let address: String = ::utils::libindy::payments::create_address(None).map_err(|x| IssuerCredError::CommonError(x))?; + let address: String = ::utils::libindy::payments::create_address(None)?; self.payment_address = Some(address.clone()); Ok(Some(PaymentInfo { payment_required: "one-time".to_string(), @@ -386,45 +385,44 @@ impl IssuerCredential { } } - fn verify_payment(&mut self) -> Result<(), u32> { + fn verify_payment(&mut self) -> VcxResult<()> { if self.price > 0 { let invoice_address = self.payment_address.as_ref() - .ok_or(error::INVALID_PAYMENT_ADDRESS.code_num)?; + .ok_or(VcxError::from(VcxErrorKind::InvalidPaymentAddress))?; let address = payments::get_address_info(&invoice_address)?; - if address.balance < self.price { return Err(error::INSUFFICIENT_TOKEN_AMOUNT.code_num); } + if address.balance < self.price { return Err(VcxError::from(VcxErrorKind::InsufficientTokenAmount)); } } Ok(()) } - fn get_payment_txn(&self) -> Result { + fn get_payment_txn(&self) -> VcxResult { trace!("IssuerCredential::get_payment_txn >>>"); match self.payment_address { Some(ref payment_address) if self.price > 0 => { - Ok(payments::PaymentTxn { + Ok(PaymentTxn { amount: self.price, credit: true, inputs: vec![payment_address.to_string()], outputs: Vec::new(), }) } - _ => Err(error::NO_PAYMENT_INFORMATION.code_num) + _ => Err(VcxError::from(VcxErrorKind::NoPaymentInformation)) } } - pub fn to_string(&self) -> String { - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json ! ( self), - }).to_string() + pub fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize credential")) } - fn from_str(s: &str) -> Result { - let data: Value = serde_json::from_str(&s)?; - let cred = serde_json::from_value(data["data"].clone())?; - Ok(cred) + fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize IssuerCredential")) } } @@ -447,26 +445,17 @@ impl IssuerCredential { } } */ -pub fn encode_attributes(attributes: &str) -> Result { - let mut attributes: serde_json::Value = match serde_json::from_str(attributes) { - Ok(x) => x, - Err(e) => { - warn!("Invalid Json for Attribute data"); - return Err(IssuerCredError::CommonError(INVALID_JSON.code_num)); - } - }; - let map = match attributes.as_object_mut() { - Some(x) => x, - None => { +pub fn encode_attributes(attributes: &str) -> VcxResult { + let mut attributes: HashMap = serde_json::from_str(attributes) + .map_err(|err| { warn!("Invalid Json for Attribute data"); - return Err(IssuerCredError::CommonError(INVALID_JSON.code_num)); - } - }; + VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize credential attributes: {}", err)) + })?; let mut dictionary = HashMap::new(); - for (attr, attr_data) in map.iter_mut() { + for (attr, attr_data) in attributes.iter_mut() { let first_attr: &str = match attr_data { // old style input such as {"address2":["101 Wilson Lane"]} serde_json::Value::Array(array_type) => { @@ -474,7 +463,7 @@ pub fn encode_attributes(attributes: &str) -> Result { Some(x) => x, None => { warn!("Cannot encode attribute: {}", error::INVALID_ATTRIBUTES_STRUCTURE.message); - return Err(IssuerCredError::CommonError(error::INVALID_ATTRIBUTES_STRUCTURE.code_num)); + return Err(VcxError::from_msg(VcxErrorKind::InvalidAttributesStructure, "Attribute value not found")); } }; @@ -487,58 +476,42 @@ pub fn encode_attributes(attributes: &str) -> Result { // anything else is an error _ => { warn!("Invalid Json for Attribute data"); - return Err(IssuerCredError::CommonError(INVALID_JSON.code_num)); + return Err(VcxError::from_msg(VcxErrorKind::InvalidJson, "Invalid Json for Attribute data")); } }; - let encoded = encode(&first_attr).map_err(|x| IssuerCredError::CommonError(x))?; + let encoded = encode(&first_attr)?; let attrib_values = json!({ -"raw": first_attr, -"encoded": encoded -}); + "raw": first_attr, + "encoded": encoded + }); dictionary.insert(attr, attrib_values); } - match serde_json::to_string_pretty(&dictionary) { - Ok(x) => Ok(x), - Err(x) => { + serde_json::to_string_pretty(&dictionary) + .map_err(|err| { warn!("Invalid Json for Attribute data"); - Err(IssuerCredError::CommonError(INVALID_JSON.code_num)) - } - } + VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Invalid Json for Attribute data: {}", err)) + }) } -pub fn get_encoded_attributes(handle: u32) -> Result { +pub fn get_encoded_attributes(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { - i.create_attributes_encodings().map_err(|ec| ec.to_error_code()) - }).map_err(|ec| IssuerCredError::CommonError(ec)) + i.create_attributes_encodings() + }) } -pub fn get_offer_uid(handle: u32) -> Result { +pub fn get_offer_uid(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { - Ok(i.get_offer_uid().clone()) + Ok(i.get_offer_uid().to_string()) }) } -pub fn get_payment_txn(handle: u32) -> Result { +pub fn get_payment_txn(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { i.get_payment_txn() - }).map_err(|ec| IssuerCredError::CommonError(ec)) -} - -fn parse_credential_req_payload(offer_uid: String, payload: String) -> Result { - debug!("parsing credentialReq payload: {:?}", payload); - - let mut my_credential_req: CredentialRequest = serde_json::from_str(&payload) - .map_err(|err| { - warn!("invalid json {}", err); - IssuerCredError::CommonError(error::INVALID_JSON.code_num) - })?; - - my_credential_req.msg_ref_id = Some(offer_uid); - - Ok(my_credential_req) + }) } pub fn issuer_credential_create(cred_def_handle: u32, @@ -546,14 +519,14 @@ pub fn issuer_credential_create(cred_def_handle: u32, issuer_did: String, credential_name: String, credential_data: String, - price: u64) -> Result { + price: u64) -> VcxResult { trace!("issuer_credential_create >>> cred_def_handle: {}, source_id: {}, issuer_did: {}, credential_name: {}, credential_data: {}, price: {}", cred_def_handle, source_id, issuer_did, credential_name, credential_data, price); - let cred_def_id = ::credential_def::get_cred_def_id(cred_def_handle).map_err(|ec| IssuerCredError::CommonError(ec.to_error_code()))?; - let rev_reg_id = ::credential_def::get_rev_reg_id(cred_def_handle).map_err(|ec| IssuerCredError::CommonError(ec.to_error_code()))?; - let tails_file = ::credential_def::get_tails_file(cred_def_handle).map_err(|ec| IssuerCredError::CommonError(ec.to_error_code()))?; - let rev_reg_def_json = ::credential_def::get_rev_reg_def(cred_def_handle).map_err(|ec| IssuerCredError::CommonError(ec.to_error_code()))?; + let cred_def_id = ::credential_def::get_cred_def_id(cred_def_handle)?; + let rev_reg_id = ::credential_def::get_rev_reg_id(cred_def_handle)?; + let tails_file = ::credential_def::get_tails_file(cred_def_handle)?; + let rev_reg_def_json = ::credential_def::get_rev_reg_def(cred_def_handle)?; let mut new_issuer_credential = IssuerCredential { credential_id: source_id.to_string(), @@ -590,128 +563,93 @@ pub fn issuer_credential_create(cred_def_handle: u32, new_issuer_credential.state = VcxStateType::VcxStateInitialized; - let new_handle = ISSUER_CREDENTIAL_MAP.add(new_issuer_credential).map_err(|key| IssuerCredError::CreateError())?; - debug!("creating issuer_credential {} with handle {}", get_source_id(new_handle).unwrap_or_default(), new_handle); + let handle = ISSUER_CREDENTIAL_MAP.add(new_issuer_credential)?; + debug!("creating issuer_credential {} with handle {}", get_source_id(handle).unwrap_or_default(), handle); - Ok(new_handle) + Ok(handle) } -pub fn update_state(handle: u32) -> Result { +pub fn update_state(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get_mut(handle, |i| { match i.update_state() { Ok(x) => Ok(x), Err(x) => Ok(i.get_state()), } - }).map_err(|ec| IssuerCredError::CommonError(ec)) + }) } -pub fn get_state(handle: u32) -> Result { +pub fn get_state(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { Ok(i.get_state()) }) } -pub fn release(handle: u32) -> Result<(), IssuerCredError> { - match ISSUER_CREDENTIAL_MAP.release(handle) { - Ok(_) => Ok(()), - Err(_) => Err(IssuerCredError::InvalidHandle()), - } +pub fn release(handle: u32) -> VcxResult<()> { + ISSUER_CREDENTIAL_MAP.release(handle) + .or(Err(VcxError::from(VcxErrorKind::InvalidIssuerCredentialHandle))) } pub fn release_all() { - match ISSUER_CREDENTIAL_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + ISSUER_CREDENTIAL_MAP.drain().ok(); } pub fn is_valid_handle(handle: u32) -> bool { ISSUER_CREDENTIAL_MAP.has_handle(handle) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { - Ok(IssuerCredential::to_string(&i)) - }).map_err(|ec| IssuerCredError::CommonError(ec)) -} - -pub fn from_string(credential_data: &str) -> Result { - let derived_credential: IssuerCredential = IssuerCredential::from_str(credential_data)?; - let source_id = derived_credential.source_id.clone(); - let new_handle = ISSUER_CREDENTIAL_MAP.add(derived_credential).map_err(|ec| IssuerCredError::CommonError(ec))?; - Ok(new_handle) + i.to_string() + }) } -pub fn send_credential_offer(handle: u32, connection_handle: u32) -> Result { - ISSUER_CREDENTIAL_MAP.get_mut(handle, |i| { - i.send_credential_offer(connection_handle).map_err(|ec| ec.to_error_code()) - }).map_err(|ec| IssuerCredError::CommonError(ec)) +pub fn from_string(credential_data: &str) -> VcxResult { + let schema: IssuerCredential = IssuerCredential::from_str(credential_data)?; + ISSUER_CREDENTIAL_MAP.add(schema) } -pub fn send_credential(handle: u32, connection_handle: u32) -> Result { +pub fn send_credential_offer(handle: u32, connection_handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get_mut(handle, |i| { - i.send_credential(connection_handle).map_err(|ec| ec.to_error_code()) - }).map_err(|ec| IssuerCredError::CommonError(ec)) + i.send_credential_offer(connection_handle) + }) } -pub fn revoke_credential(handle: u32) -> Result<(), u32> { +pub fn send_credential(handle: u32, connection_handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get_mut(handle, |i| { - i.revoke_cred().map_err(|ec| ec.to_error_code()) + i.send_credential(connection_handle) }) } -fn get_offer_details(response: &str) -> Result { - match serde_json::from_str(response) { - Ok(json) => { - let json: serde_json::Value = json; - let detail = match json["uid"].as_str() { - Some(x) => x, - None => { - warn!("response had no uid"); - return Err(IssuerCredError::CommonError(error::INVALID_JSON.code_num)); - } - }; - Ok(String::from(detail)) - } - Err(_) => { - warn!("get_messages called without a valid response from server"); - Err(IssuerCredError::CommonError(error::INVALID_JSON.code_num)) - } - } -} - -pub fn set_credential_request(handle: u32, credential_request: CredentialRequest) -> Result { +pub fn revoke_credential(handle: u32) -> VcxResult<()> { ISSUER_CREDENTIAL_MAP.get_mut(handle, |i| { - i.set_credential_request(credential_request.clone()) - }).map_err(|ec| IssuerCredError::CommonError(ec)) + i.revoke_cred() + }) } -pub fn convert_to_map(s: &str) -> Result, IssuerCredError> { - let v: serde_json::Map = match serde_json::from_str(s) { - Ok(m) => m, - Err(_) => { +pub fn convert_to_map(s: &str) -> VcxResult> { + serde_json::from_str(s) + .map_err(|err| { warn!("{}", error::INVALID_ATTRIBUTES_STRUCTURE.message); - return Err(IssuerCredError::CommonError(error::INVALID_ATTRIBUTES_STRUCTURE.code_num)); - } - }; - Ok(v) + VcxError::from_msg(VcxErrorKind::InvalidAttributesStructure, error::INVALID_ATTRIBUTES_STRUCTURE.message) + }) } -pub fn get_credential_attributes(handle: u32) -> Result { +pub fn get_credential_attributes(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { - Ok(i.get_credential_attributes().clone()) + Ok(i.get_credential_attributes().to_string()) }) } -pub fn get_source_id(handle: u32) -> Result { +pub fn get_source_id(handle: u32) -> VcxResult { ISSUER_CREDENTIAL_MAP.get(handle, |i| { - Ok(i.get_source_id().clone()) + Ok(i.get_source_id().to_string()) }) } #[cfg(test)] pub mod tests { use super::*; + use serde_json::Value; use settings; use connection::tests::build_test_connection; use credential_request::CredentialRequest; @@ -724,7 +662,6 @@ pub mod tests { wallet::get_wallet_handle, wallet}, get_temp_dir_path, }; - use error::{issuer_cred::IssuerCredError}; static DEFAULT_CREDENTIAL_NAME: &str = "Credential"; static DEFAULT_CREDENTIAL_ID: &str = "defaultCredentialId"; @@ -952,8 +889,7 @@ pub mod tests { let connection_handle = build_test_connection(); set_libindy_rc(error::TIMEOUT_LIBINDY_ERROR.code_num); - assert_eq!(credential.send_credential(connection_handle), - Err(IssuerCredError::CommonError(error::TIMEOUT_LIBINDY_ERROR.code_num))); + assert_eq!(credential.send_credential(connection_handle).unwrap_err().kind(), VcxErrorKind::Common(1038)); assert_eq!(credential.msg_uid, "1234"); assert_eq!(credential.state, VcxStateType::VcxStateRequestReceived); // Retry sending the credential, use the mocked http. Show that you can retry sending the credential @@ -1060,7 +996,7 @@ pub mod tests { error!("basic_add_attribute_encoding test should raise error."); assert_ne!(1, 1); } - Err(e) => assert_eq!(e, IssuerCredError::CommonError(error::INVALID_JSON.code_num)), + Err(e) => assert_eq!(e.kind(), VcxErrorKind::InvalidJson) } } @@ -1085,19 +1021,19 @@ pub mod tests { let h4 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), "{\"attr\":\"value\"}".to_owned(), 1).unwrap(); let h5 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), "{\"attr\":\"value\"}".to_owned(), 1).unwrap(); release_all(); - assert_eq!(release(h1), Err(IssuerCredError::InvalidHandle())); - assert_eq!(release(h2), Err(IssuerCredError::InvalidHandle())); - assert_eq!(release(h3), Err(IssuerCredError::InvalidHandle())); - assert_eq!(release(h4), Err(IssuerCredError::InvalidHandle())); - assert_eq!(release(h5), Err(IssuerCredError::InvalidHandle())); + assert_eq!(release(h1).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); + assert_eq!(release(h2).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); + assert_eq!(release(h3).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); + assert_eq!(release(h4).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); + assert_eq!(release(h5).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); } #[test] fn test_errors() { init!("false"); let invalid_handle = 478620; - assert_eq!(to_string(invalid_handle).err(), Some(IssuerCredError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); - assert_eq!(release(invalid_handle).err(), Some(IssuerCredError::InvalidHandle())); + assert_eq!(to_string(invalid_handle).unwrap_err().kind(), VcxErrorKind::InvalidHandle); + assert_eq!(release(invalid_handle).unwrap_err().kind(), VcxErrorKind::InvalidIssuerCredentialHandle); } #[test] @@ -1141,11 +1077,11 @@ pub mod tests { // Err - Wrong payment amount credential.price = 200; - assert_eq!(credential.verify_payment(), Err(error::INSUFFICIENT_TOKEN_AMOUNT.code_num)); + assert_eq!(credential.verify_payment().unwrap_err().kind(), VcxErrorKind::InsufficientTokenAmount); // Err - address not set credential.payment_address = None; - assert_eq!(credential.verify_payment(), Err(error::INVALID_PAYMENT_ADDRESS.code_num)); + assert_eq!(credential.verify_payment().unwrap_err().kind(), VcxErrorKind::InvalidPaymentAddress); } #[test] @@ -1179,15 +1115,15 @@ pub mod tests { credential.tails_file = Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()); credential.cred_rev_id = None; credential.rev_reg_id = None; - assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + assert_eq!(credential.revoke_cred().unwrap_err().kind(), VcxErrorKind::InvalidRevocationDetails); credential.tails_file = None; credential.cred_rev_id = Some(CRED_REV_ID.to_string()); credential.rev_reg_id = None; - assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + assert_eq!(credential.revoke_cred().unwrap_err().kind(), VcxErrorKind::InvalidRevocationDetails); credential.tails_file = None; credential.cred_rev_id = None; credential.rev_reg_id = Some(REV_REG_ID.to_string()); - assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + assert_eq!(credential.revoke_cred().unwrap_err().kind(), VcxErrorKind::InvalidRevocationDetails); credential.tails_file = Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()); credential.cred_rev_id = Some(CRED_REV_ID.to_string()); diff --git a/vcx/libvcx/src/lib.rs b/vcx/libvcx/src/lib.rs index baa39c90d5..4a760c34f2 100644 --- a/vcx/libvcx/src/lib.rs +++ b/vcx/libvcx/src/lib.rs @@ -16,6 +16,8 @@ extern crate futures; extern crate log; extern crate log4rs; +extern crate libc; + #[macro_use] extern crate serde_derive; @@ -31,6 +33,10 @@ extern crate regex; extern crate uuid; +extern crate failure; + +extern crate rmp_serde; + #[macro_use] pub mod utils; pub mod settings; diff --git a/vcx/libvcx/src/messages/agent_utils.rs b/vcx/libvcx/src/messages/agent_utils.rs index c0752a214d..c3a65af351 100644 --- a/vcx/libvcx/src/messages/agent_utils.rs +++ b/vcx/libvcx/src/messages/agent_utils.rs @@ -1,10 +1,11 @@ use settings; -use utils::constants::*; use messages::{A2AMessage, A2AMessageV1, A2AMessageV2, A2AMessageKinds, prepare_message_for_agency, parse_response_from_agency}; use messages::message_type::MessageTypes; +use utils::constants::*; use utils::{error, httpclient}; use utils::libindy::{wallet, anoncreds}; use utils::libindy::signus::create_and_store_my_did; +use error::prelude::*; #[derive(Serialize, Deserialize, Debug)] pub struct Connect { @@ -126,11 +127,12 @@ pub struct Config { } -pub fn connect_register_provision(config: &str) -> Result { +pub fn connect_register_provision(config: &str) -> VcxResult { trace!("connect_register_provision >>> config: {:?}", config); trace!("***Registering with agency"); - let my_config: Config = serde_json::from_str(&config).or(Err(error::INVALID_CONFIGURATION.code_num))?; + let my_config: Config = ::serde_json::from_str(&config) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidConfiguration, format!("Cannot parse config: {}", err)))?; let wallet_name = my_config.wallet_name.unwrap_or(settings::DEFAULT_WALLET_NAME.to_string()); @@ -156,7 +158,8 @@ pub fn connect_register_provision(config: &str) -> Result { } wallet::init_wallet(&wallet_name, my_config.wallet_type.as_ref().map(String::as_str), - my_config.storage_config.as_ref().map(String::as_str), my_config.storage_credentials.as_ref().map(String::as_str))?; + my_config.storage_config.as_ref().map(String::as_str), + my_config.storage_credentials.as_ref().map(String::as_str))?; trace!("initialized wallet"); anoncreds::libindy_prover_create_master_secret(::settings::DEFAULT_LINK_SECRET_ALIAS).ok(); // If MS is already in wallet then just continue @@ -221,7 +224,7 @@ pub fn connect_register_provision(config: &str) -> Result { Ok(final_config.to_string()) } -fn onboarding_v1(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, String), u32> { +fn onboarding_v1(my_did: &str, my_vk: &str, agency_did: &str) -> VcxResult<(String, String)> { /* STEP 1 - CONNECT */ if settings::test_agency_mode_enabled() { httpclient::set_next_u8_response(CONNECTED_RESPONSE.to_vec()); @@ -236,7 +239,7 @@ fn onboarding_v1(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let ConnectResponse { from_vk: agency_pw_vk, from_did: agency_pw_did, .. } = match response.remove(0) { A2AMessage::Version1(A2AMessageV1::ConnectResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of ConnectResponse")) }; settings::set_config_value(settings::CONFIG_REMOTE_TO_SDK_VERKEY, &agency_pw_vk); @@ -255,7 +258,7 @@ fn onboarding_v1(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let _response: SignUpResponse = match response.remove(0) { A2AMessage::Version1(A2AMessageV1::SignUpResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of SignUpResponse")) }; /* STEP 3 - CREATE AGENT */ @@ -272,14 +275,14 @@ fn onboarding_v1(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let response: CreateAgentResponse = match response.remove(0) { A2AMessage::Version1(A2AMessageV1::CreateAgentResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of CreateAgentResponse")) }; Ok((response.from_did, response.from_vk)) } // it will be changed next -fn onboarding_v2(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, String), u32> { +fn onboarding_v2(my_did: &str, my_vk: &str, agency_did: &str) -> VcxResult<(String, String)> { /* STEP 1 - CONNECT */ let message = A2AMessage::Version2( A2AMessageV2::Connect(Connect::build(my_did, my_vk)) @@ -290,7 +293,7 @@ fn onboarding_v2(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let ConnectResponse { from_vk: agency_pw_vk, from_did: agency_pw_did, .. } = match response.remove(0) { A2AMessage::Version2(A2AMessageV2::ConnectResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of ConnectResponse")) }; settings::set_config_value(settings::CONFIG_REMOTE_TO_SDK_VERKEY, &agency_pw_vk); @@ -305,7 +308,7 @@ fn onboarding_v2(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let _response: SignUpResponse = match response.remove(0) { A2AMessage::Version2(A2AMessageV2::SignUpResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of SignUpResponse")) }; /* STEP 3 - CREATE AGENT */ @@ -318,13 +321,13 @@ fn onboarding_v2(my_did: &str, my_vk: &str, agency_did: &str) -> Result<(String, let response: CreateAgentResponse = match response.remove(0) { A2AMessage::Version2(A2AMessageV2::CreateAgentResponse(resp)) => resp, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of CreateAgentResponse")) }; Ok((response.from_did, response.from_vk)) } -pub fn update_agent_info(id: &str, value: &str) -> Result<(), u32> { +pub fn update_agent_info(id: &str, value: &str) -> VcxResult<()> { trace!("update_agent_info >>> id: {}, value: {}", id, value); let to_did = settings::get_config_value(settings::CONFIG_REMOTE_TO_SDK_DID)?; @@ -345,7 +348,7 @@ pub fn update_agent_info(id: &str, value: &str) -> Result<(), u32> { } } -fn update_agent_info_v1(to_did: &str, com_method: ComMethod) -> Result<(), u32> { +fn update_agent_info_v1(to_did: &str, com_method: ComMethod) -> VcxResult<()> { if settings::test_agency_mode_enabled() { httpclient::set_next_u8_response(REGISTER_RESPONSE.to_vec()); } @@ -357,7 +360,7 @@ fn update_agent_info_v1(to_did: &str, com_method: ComMethod) -> Result<(), u32> Ok(()) } -fn update_agent_info_v2(to_did: &str, com_method: ComMethod) -> Result<(), u32> { +fn update_agent_info_v2(to_did: &str, com_method: ComMethod) -> VcxResult<()> { let message = A2AMessage::Version2( A2AMessageV2::UpdateConnectionMethod(UpdateConnectionMethod::build(com_method)) ); @@ -365,10 +368,11 @@ fn update_agent_info_v2(to_did: &str, com_method: ComMethod) -> Result<(), u32> Ok(()) } -fn send_message_to_agency(message: &A2AMessage, did: &str) -> Result, u32> { +fn send_message_to_agency(message: &A2AMessage, did: &str) -> VcxResult> { let data = prepare_message_for_agency(message, &did)?; - let response = httpclient::post_u8(&data).or(Err(error::INVALID_HTTP_RESPONSE.code_num))?; + let response = httpclient::post_u8(&data) + .map_err(|err| err.map(VcxErrorKind::InvalidHttpResponse, error::INVALID_HTTP_RESPONSE.message))?; parse_response_from_agency(&response) } @@ -422,9 +426,6 @@ mod tests { settings::set_defaults(); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "true"); - match update_agent_info("123", "value") { - Ok(_) => assert_eq!(0, 0), - Err(x) => assert_eq!(x, 0), // should fail here - }; + update_agent_info("123", "value").unwrap(); } } diff --git a/vcx/libvcx/src/messages/create_key.rs b/vcx/libvcx/src/messages/create_key.rs index 3ac99a9a09..655df183d6 100644 --- a/vcx/libvcx/src/messages/create_key.rs +++ b/vcx/libvcx/src/messages/create_key.rs @@ -1,8 +1,9 @@ use settings; use messages::*; use messages::message_type::MessageTypes; -use utils::{httpclient, error}; +use utils::httpclient; use utils::constants::CREATE_KEYS_RESPONSE; +use error::prelude::*; #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] @@ -51,19 +52,19 @@ impl CreateKeyBuilder { } } - pub fn for_did(&mut self, did: &str) -> Result<&mut Self, u32> { + pub fn for_did(&mut self, did: &str) -> VcxResult<&mut Self> { validation::validate_did(did)?; self.for_did = did.to_string(); Ok(self) } - pub fn for_verkey(&mut self, verkey: &str) -> Result<&mut Self, u32> { + pub fn for_verkey(&mut self, verkey: &str) -> VcxResult<&mut Self> { validation::validate_verkey(verkey)?; self.for_verkey = verkey.to_string(); Ok(self) } - pub fn send_secure(&self) -> Result<(String, String), u32> { + pub fn send_secure(&self) -> VcxResult<(String, String)> { trace!("CreateKeyMsg::send >>>"); if settings::test_agency_mode_enabled() { @@ -72,12 +73,12 @@ impl CreateKeyBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; self.parse_response(&response) } - fn prepare_request(&self) -> Result, u32> { + fn prepare_request(&self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( @@ -94,7 +95,7 @@ impl CreateKeyBuilder { prepare_message_for_agency(&message, &agency_did) } - fn parse_response(&self, response: &Vec) -> Result<(String, String), u32> { + fn parse_response(&self, response: &Vec) -> VcxResult<(String, String)> { trace!("parse_response >>>"); let mut response = parse_response_from_agency(response)?; @@ -102,7 +103,7 @@ impl CreateKeyBuilder { match response.remove(0) { A2AMessage::Version1(A2AMessageV1::CreateKeyResponse(res)) => Ok((res.for_did, res.for_verkey)), A2AMessage::Version2(A2AMessageV2::CreateKeyResponse(res)) => Ok((res.for_did, res.for_verkey)), - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from(VcxErrorKind::InvalidHttpResponse)) } } } @@ -160,7 +161,7 @@ mod tests { fn test_create_key_set_invalid_did_errors() { let for_did = "11235yBzrpJQmNyZzgoT"; let res = create_keys().for_did(for_did).unwrap_err(); - assert_eq!(res, error::INVALID_DID.code_num); + assert_eq!(res.kind(), VcxErrorKind::InvalidDid); } } diff --git a/vcx/libvcx/src/messages/get_message.rs b/vcx/libvcx/src/messages/get_message.rs index ee81665874..40374aabb3 100644 --- a/vcx/libvcx/src/messages/get_message.rs +++ b/vcx/libvcx/src/messages/get_message.rs @@ -1,7 +1,8 @@ use settings; use messages::*; use messages::message_type::MessageTypes; -use utils::{httpclient, error}; +use utils::httpclient; +use error::prelude::*; #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] @@ -86,35 +87,35 @@ impl GetMessagesBuilder { } } - pub fn uid(&mut self, uids: Option>) -> Result<&mut Self, u32> { + pub fn uid(&mut self, uids: Option>) -> VcxResult<&mut Self> { //Todo: validate msg_uid?? self.uids = uids; Ok(self) } - pub fn status_codes(&mut self, status_codes: Option>) -> Result<&mut Self, u32> { + pub fn status_codes(&mut self, status_codes: Option>) -> VcxResult<&mut Self> { self.status_codes = status_codes; Ok(self) } - pub fn pairwise_dids(&mut self, pairwise_dids: Option>) -> Result<&mut Self, u32> { + pub fn pairwise_dids(&mut self, pairwise_dids: Option>) -> VcxResult<&mut Self> { //Todo: validate msg_uid?? self.pairwise_dids = pairwise_dids; Ok(self) } - pub fn include_edge_payload(&mut self, payload: &str) -> Result<&mut Self, u32> { + pub fn include_edge_payload(&mut self, payload: &str) -> VcxResult<&mut Self> { //todo: is this a json value, String?? self.exclude_payload = Some(payload.to_string()); Ok(self) } - pub fn send_secure(&mut self) -> Result, u32> { + pub fn send_secure(&mut self) -> VcxResult> { trace!("GetMessages::send >>>"); let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; if settings::test_agency_mode_enabled() && response.len() == 0 { return Ok(Vec::new()); @@ -123,7 +124,7 @@ impl GetMessagesBuilder { self.parse_response(response) } - fn parse_response(&self, response: Vec) -> Result, u32> { + fn parse_response(&self, response: Vec) -> VcxResult> { trace!("parse_get_messages_response >>>"); let mut response = parse_response_from_agency(&response)?; @@ -131,16 +132,16 @@ impl GetMessagesBuilder { match response.remove(0) { A2AMessage::Version1(A2AMessageV1::GetMessagesResponse(res)) => Ok(res.msgs), A2AMessage::Version2(A2AMessageV2::GetMessagesResponse(res)) => Ok(res.msgs), - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of GetMessagesResponse")) } } - pub fn download_messages(&mut self) -> Result, u32> { + pub fn download_messages(&mut self) -> VcxResult> { trace!("GetMessages::download >>>"); let data = self.prepare_download_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; if settings::test_agency_mode_enabled() && response.len() == 0 { return Ok(Vec::new()); @@ -151,7 +152,7 @@ impl GetMessagesBuilder { Ok(response) } - fn prepare_download_request(&self) -> Result, u32> { + fn prepare_download_request(&self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( @@ -178,14 +179,14 @@ impl GetMessagesBuilder { prepare_message_for_agency(&message, &agency_did) } - fn parse_download_messages_response(response: Vec) -> Result, u32> { + fn parse_download_messages_response(response: Vec) -> VcxResult> { trace!("parse_get_connection_messages_response >>>"); let mut response = parse_response_from_agency(&response)?; let msgs = match response.remove(0) { A2AMessage::Version1(A2AMessageV1::GetMessagesByConnectionsResponse(res)) => res.msgs, A2AMessage::Version2(A2AMessageV2::GetMessagesByConnectionsResponse(res)) => res.msgs, - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of GetMessagesByConnectionsResponse")) }; msgs @@ -210,7 +211,7 @@ impl GeneralMessage for GetMessagesBuilder { fn set_to_did(&mut self, to_did: String) { self.to_did = to_did; } fn set_to_vk(&mut self, to_vk: String) { self.to_vk = to_vk; } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( @@ -277,7 +278,7 @@ impl Message { } } -pub fn get_connection_messages(pw_did: &str, pw_vk: &str, agent_did: &str, agent_vk: &str, msg_uid: Option>) -> Result, u32> { +pub fn get_connection_messages(pw_did: &str, pw_vk: &str, agent_did: &str, agent_vk: &str, msg_uid: Option>) -> VcxResult> { trace!("get_connection_messages >>> pw_did: {}, pw_vk: {}, agent_vk: {}, msg_uid: {:?}", pw_did, pw_vk, agent_vk, msg_uid); @@ -288,16 +289,13 @@ pub fn get_connection_messages(pw_did: &str, pw_vk: &str, agent_did: &str, agent .agent_vk(&agent_vk)? .uid(msg_uid)? .send_secure() - .map_err(|err| { - error!("could not post get_messages: {}", err); - error::POST_MSG_FAILURE.code_num - })?; + .map_err(|err| err.map(VcxErrorKind::PostMessageFailed, "Cannot get messages"))?; trace!("message returned: {:?}", response); Ok(response) } -pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result<(String, Vec), u32> { +pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, agent_vk: &str) -> VcxResult<(String, Vec)> { trace!("get_ref_msg >>> msg_id: {}, pw_did: {}, pw_vk: {}, agent_did: {}, agent_vk: {}", msg_id, pw_did, pw_vk, agent_did, agent_vk); @@ -306,7 +304,7 @@ pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, age let msg_id = match message.get(0).as_ref().and_then(|message| message.ref_msg_id.as_ref()) { Some(ref ref_msg_id) if message[0].status_code == MessageStatusCode::Accepted => ref_msg_id.to_string(), - _ => return Err(error::NOT_READY.code_num), + _ => return Err(VcxError::from_msg(VcxErrorKind::NotReady, "Cannot find referent message")), }; let message: Vec = get_connection_messages(pw_did, pw_vk, agent_did, agent_vk, Some(vec![msg_id]))?; @@ -319,11 +317,11 @@ pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, age // TODO: check returned verkey Ok((message[0].uid.clone(), payload.to_owned())) } - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Cannot find referent message")), } } -pub fn download_messages(pairwise_dids: Option>, status_codes: Option>, uids: Option>) -> Result, u32> { +pub fn download_messages(pairwise_dids: Option>, status_codes: Option>, uids: Option>) -> VcxResult> { trace!("download_messages >>> pairwise_dids: {:?}, status_codes: {:?}, uids: {:?}", pairwise_dids, status_codes, uids); @@ -337,8 +335,9 @@ pub fn download_messages(pairwise_dids: Option>, status_codes: Optio let codes = codes .iter() .map(|code| - serde_json::from_str::(&format!("\"{}\"", code)).or(Err(error::INVALID_JSON.code_num)) - ).collect::, u32>>()?; + ::serde_json::from_str::(&format!("\"{}\"", code)) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot parse message status code: {}", err))) + ).collect::>>()?; Some(codes) } None => None @@ -467,7 +466,7 @@ mod tests { // Agency returns a bad request response for invalid dids let invalid_did = "abc".to_string(); let bad_req = download_messages(Some(vec![invalid_did]), None, None); - assert_eq!(bad_req, Err(error::POST_MSG_FAILURE.code_num)); + assert_eq!(bad_req.unwrap_err().kind(), VcxErrorKind::PostMessageFailed); teardown!("agency"); } } diff --git a/vcx/libvcx/src/messages/invite.rs b/vcx/libvcx/src/messages/invite.rs index 3cf1fcd9ee..876c850775 100644 --- a/vcx/libvcx/src/messages/invite.rs +++ b/vcx/libvcx/src/messages/invite.rs @@ -2,9 +2,10 @@ use settings; use messages::*; use messages::message_type::{MessageTypes, MessageTypeV1, MessageTypeV2}; use messages::payload::Thread; -use utils::{httpclient, error}; +use utils::httpclient; use utils::constants::*; use utils::uuid::uuid; +use error::prelude::*; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] pub struct SendInviteMessageDetails { @@ -222,13 +223,13 @@ impl SendInviteBuilder { } } - pub fn key_delegate(&mut self, key: &str) -> Result<&mut Self, u32> { + pub fn key_delegate(&mut self, key: &str) -> VcxResult<&mut Self> { validation::validate_key_delegate(key)?; self.payload.key_dlg_proof.agent_delegated_key = key.to_string(); Ok(self) } - pub fn public_did(&mut self, did: Option<&str>) -> Result<&mut Self, u32> { + pub fn public_did(&mut self, did: Option<&str>) -> VcxResult<&mut Self> { if did.is_some() { self.payload.include_public_did = true; } @@ -236,7 +237,7 @@ impl SendInviteBuilder { Ok(self) } - pub fn phone_number(&mut self, phone_number: Option<&str>) -> Result<&mut Self, u32> { + pub fn phone_number(&mut self, phone_number: Option<&str>) -> VcxResult<&mut Self> { if let Some(ref p_num) = phone_number { validation::validate_phone_number(p_num)?; self.payload.phone_no = phone_number.map(String::from); @@ -244,12 +245,12 @@ impl SendInviteBuilder { Ok(self) } - pub fn thread(&mut self, thread: &Thread) -> Result<&mut Self, u32> { + pub fn thread(&mut self, thread: &Thread) -> VcxResult<&mut Self> { self.thread = thread.clone(); Ok(self) } - pub fn generate_signature(&mut self) -> Result<(), u32> { + pub fn generate_signature(&mut self) -> VcxResult<()> { let signature = format!("{}{}", self.payload.key_dlg_proof.agent_did, self.payload.key_dlg_proof.agent_delegated_key); let signature = ::utils::libindy::crypto::sign(&self.to_vk, signature.as_bytes())?; let signature = base64::encode(&signature); @@ -257,7 +258,7 @@ impl SendInviteBuilder { Ok(()) } - pub fn send_secure(&mut self) -> Result<(InviteDetail, String), u32> { + pub fn send_secure(&mut self) -> VcxResult<(InviteDetail, String)> { trace!("SendInvite::send >>>"); if settings::test_agency_mode_enabled() { @@ -266,14 +267,14 @@ impl SendInviteBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; let (invite, url) = self.parse_response(response)?; Ok((invite, url)) } - fn parse_response(&self, response: Vec) -> Result<(InviteDetail, String), u32> { + fn parse_response(&self, response: Vec) -> VcxResult<(InviteDetail, String)> { let mut response = parse_response_from_agency(&response)?; let index = match settings::get_protocol_type() { @@ -287,7 +288,7 @@ impl SendInviteBuilder { Ok((res.invite_detail, res.url_to_invite_detail)), A2AMessage::Version2(A2AMessageV2::ConnectionRequestResponse(res)) => Ok((res.invite_detail, res.url_to_invite_detail)), - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of ConnectionRequestResponse")) } } } @@ -307,7 +308,6 @@ impl AcceptInviteBuilder { pub fn create() -> AcceptInviteBuilder { trace!("AcceptInvite::create_message >>>"); - AcceptInviteBuilder { to_did: String::new(), to_vk: String::new(), @@ -325,38 +325,38 @@ impl AcceptInviteBuilder { } } - pub fn key_delegate(&mut self, key: &str) -> Result<&mut Self, u32> { + pub fn key_delegate(&mut self, key: &str) -> VcxResult<&mut Self> { validation::validate_key_delegate(key)?; self.payload.key_dlg_proof.agent_delegated_key = key.to_string(); Ok(self) } - pub fn sender_details(&mut self, details: &SenderDetail) -> Result<&mut Self, u32> { + pub fn sender_details(&mut self, details: &SenderDetail) -> VcxResult<&mut Self> { self.payload.sender_detail = Some(details.clone()); Ok(self) } - pub fn sender_agency_details(&mut self, details: &SenderAgencyDetail) -> Result<&mut Self, u32> { + pub fn sender_agency_details(&mut self, details: &SenderAgencyDetail) -> VcxResult<&mut Self> { self.payload.sender_agency_detail = Some(details.clone()); Ok(self) } - pub fn answer_status_code(&mut self, code: &MessageStatusCode) -> Result<&mut Self, u32> { + pub fn answer_status_code(&mut self, code: &MessageStatusCode) -> VcxResult<&mut Self> { self.payload.answer_status_code = Some(code.clone()); Ok(self) } - pub fn reply_to(&mut self, id: &str) -> Result<&mut Self, u32> { + pub fn reply_to(&mut self, id: &str) -> VcxResult<&mut Self> { self.reply_to_msg_id = Some(id.to_string()); Ok(self) } - pub fn thread(&mut self, thread: &Thread) -> Result<&mut Self, u32> { + pub fn thread(&mut self, thread: &Thread) -> VcxResult<&mut Self> { self.thread = thread.clone(); Ok(self) } - pub fn generate_signature(&mut self) -> Result<(), u32> { + pub fn generate_signature(&mut self) -> VcxResult<()> { let signature = format!("{}{}", self.payload.key_dlg_proof.agent_did, self.payload.key_dlg_proof.agent_delegated_key); let signature = crypto::sign(&self.to_vk, signature.as_bytes())?; let signature = base64::encode(&signature); @@ -364,7 +364,7 @@ impl AcceptInviteBuilder { Ok(()) } - pub fn send_secure(&mut self) -> Result { + pub fn send_secure(&mut self) -> VcxResult { trace!("AcceptInvite::send >>>"); if settings::test_agency_mode_enabled() { @@ -373,18 +373,18 @@ impl AcceptInviteBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; self.parse_response(response) } - fn parse_response(&self, response: Vec) -> Result { + fn parse_response(&self, response: Vec) -> VcxResult { let mut response = parse_response_from_agency(&response)?; match response.remove(0) { A2AMessage::Version1(A2AMessageV1::MessageCreated(res)) => Ok(res.uid), A2AMessage::Version2(A2AMessageV2::ConnectionRequestAnswerResponse(res)) => Ok(res.id), - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of ConnectionAnswerResponse")) } } } @@ -408,7 +408,7 @@ impl GeneralMessage for SendInviteBuilder { fn set_to_vk(&mut self, to_vk: String) { self.to_vk = to_vk; } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { self.generate_signature()?; let messages = @@ -464,7 +464,7 @@ impl GeneralMessage for AcceptInviteBuilder { fn set_to_did(&mut self, to_did: String) { self.to_did = to_did; } fn set_to_vk(&mut self, to_vk: String) { self.to_vk = to_vk; } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { self.generate_signature()?; let messages = @@ -517,9 +517,10 @@ pub struct AcceptanceDetails { pub sender_detail: SenderDetail, } -pub fn parse_invitation_acceptance_details(payload: Vec) -> Result { +pub fn parse_invitation_acceptance_details(payload: Vec) -> VcxResult { debug!("parsing invitation acceptance details: {:?}", payload); - let response: AcceptanceDetails = rmp_serde::from_slice(&payload[..]).or(Err(error::INVALID_MSGPACK.code_num))?; + let response: AcceptanceDetails = rmp_serde::from_slice(&payload[..]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Cannot decode acceptance details: {:?}", err)))?; Ok(response.sender_detail) } diff --git a/vcx/libvcx/src/messages/message_type.rs b/vcx/libvcx/src/messages/message_type.rs index 27ebaa4685..338d239f79 100644 --- a/vcx/libvcx/src/messages/message_type.rs +++ b/vcx/libvcx/src/messages/message_type.rs @@ -4,7 +4,7 @@ use serde::{de, Deserializer, Deserialize, Serializer, Serialize}; use serde_json::Value; use regex::{Regex, Match}; use messages::A2AMessageKinds; -use utils::error; +use error::prelude::*; pub const MESSAGE_VERSION_V1: &str = "1.0"; pub const DID: &str = "did:sov:123456789abcdefghi1234"; @@ -112,7 +112,7 @@ impl ::std::string::ToString for MessageFamilies { } -fn parse_message_type(message_type: &str) -> Result<(String, String, String, String), u32> { +fn parse_message_type(message_type: &str) -> VcxResult<(String, String, String, String)> { lazy_static! { static ref RE: Regex = Regex::new(r"(?x) (?P[\d\w:]*); @@ -134,7 +134,7 @@ fn parse_message_type(message_type: &str) -> Result<(String, String, String, Str Some((did.to_string(), family.to_string(), version.to_string(), type_.to_string())), _ => None } - }).ok_or(error::INVALID_OPTION.code_num) // TODO: Check Error + }).ok_or(VcxError::from_msg(VcxErrorKind::InvalidOption, "Cannot parse @type")) } impl<'de> Deserialize<'de> for MessageTypeV2 { diff --git a/vcx/libvcx/src/messages/mod.rs b/vcx/libvcx/src/messages/mod.rs index 3a0e355bea..22e7c8397f 100644 --- a/vcx/libvcx/src/messages/mod.rs +++ b/vcx/libvcx/src/messages/mod.rs @@ -14,7 +14,6 @@ pub mod payload; use std::u8; use settings; use utils::libindy::crypto; -use utils::error; use self::create_key::{CreateKeyBuilder, CreateKey, CreateKeyResponse}; use self::update_connection::{DeleteConnectionBuilder, UpdateConnection, UpdateConnectionResponse}; use self::update_profile::{UpdateProfileDataBuilder, UpdateConfigs, UpdateConfigsResponse}; @@ -28,6 +27,7 @@ use self::update_message::{UpdateMessageStatusByConnections, UpdateMessageStatus use self::proofs::proof_request::ProofRequestMessage; use self::agent_utils::{Connect, ConnectResponse, SignUp, SignUpResponse, CreateAgent, CreateAgentResponse, UpdateConnectionMethod}; use self::message_type::*; +use error::prelude::*; use serde::{de, Deserialize, Deserializer, ser, Serialize, Serializer}; use serde_json::Value; @@ -566,89 +566,6 @@ impl<'de> Deserialize<'de> for RemoteMessageType { } } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] -#[serde(untagged)] -pub enum PayloadTypes { - PayloadTypeV1(PayloadTypeV1), - PayloadTypeV2(PayloadTypeV2), -} - -#[derive(Clone, Deserialize, Serialize, Debug, PartialEq)] -pub struct PayloadTypeV1 { - name: String, - ver: String, - fmt: String, -} - -type PayloadTypeV2 = MessageTypeV2; - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum PayloadKinds { - CredOffer, - CredReq, - Cred, - Proof, - ProofRequest, - Other(String) -} - -impl PayloadKinds { - fn family(&self) -> MessageFamilies { - match self { - PayloadKinds::CredOffer => MessageFamilies::CredentialExchange, - PayloadKinds::CredReq => MessageFamilies::CredentialExchange, - PayloadKinds::Cred => MessageFamilies::CredentialExchange, - PayloadKinds::Proof => MessageFamilies::CredentialExchange, - PayloadKinds::ProofRequest => MessageFamilies::CredentialExchange, - PayloadKinds::Other(family) => MessageFamilies::Unknown(family.to_string()), - } - } - - fn name<'a>(&'a self) -> &'a str { - match settings::get_protocol_type() { - settings::ProtocolTypes::V1 => { - match self { - PayloadKinds::CredOffer => "CRED_OFFER", - PayloadKinds::CredReq => "CRED_REQ", - PayloadKinds::Cred => "CRED", - PayloadKinds::ProofRequest => "PROOF_REQUEST", - PayloadKinds::Proof => "PROOF", - PayloadKinds::Other(kind) => kind, - } - } - settings::ProtocolTypes::V2 => { - match self { - PayloadKinds::CredOffer => "credential-offer", - PayloadKinds::CredReq => "credential-request", - PayloadKinds::Cred => "credential", - PayloadKinds::ProofRequest => "presentation-request", - PayloadKinds::Proof => "presentation", - PayloadKinds::Other(kind) => kind, - } - } - } - } -} - -impl PayloadTypes { - pub fn build_v1(kind: PayloadKinds, fmt: &str) -> PayloadTypes { - PayloadTypes::PayloadTypeV1(PayloadTypeV1 { - name: kind.name().to_string(), - ver: MESSAGE_VERSION_V1.to_string(), - fmt: fmt.to_string(), - }) - } - - pub fn build_v2(kind: PayloadKinds) -> PayloadTypes { - PayloadTypes::PayloadTypeV2(PayloadTypeV2 { - did: DID.to_string(), - family: kind.family(), - version: kind.family().version().to_string(), - type_: kind.name().to_string(), - }) - } -} - #[derive(Clone, Debug, PartialEq)] pub enum MessageStatusCode { Created, @@ -782,18 +699,20 @@ impl A2AMessageKinds { } } -pub fn prepare_message_for_agency(message: &A2AMessage, agency_did: &str) -> Result, u32> { +pub fn prepare_message_for_agency(message: &A2AMessage, agency_did: &str) -> VcxResult> { match settings::get_protocol_type() { settings::ProtocolTypes::V1 => bundle_for_agency_v1(message, &agency_did), settings::ProtocolTypes::V2 => pack_for_agency_v2(message, agency_did) } } -fn bundle_for_agency_v1(message: &A2AMessage, agency_did: &str) -> Result, u32> { +fn bundle_for_agency_v1(message: &A2AMessage, agency_did: &str) -> VcxResult> { let agent_vk = settings::get_config_value(settings::CONFIG_REMOTE_TO_SDK_VERKEY)?; let my_vk = settings::get_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY)?; - let message = rmp_serde::to_vec_named(&message).or(Err(error::UNKNOWN_ERROR.code_num))?; + let message = rmp_serde::to_vec_named(&message) + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, format!("Cannot encode message: {}", err)))?; + let message = Bundled::create(message).encode()?; let message = crypto::prep_msg(&my_vk, &agent_vk, &message[..])?; @@ -801,46 +720,51 @@ fn bundle_for_agency_v1(message: &A2AMessage, agency_did: &str) -> Result Result, u32> { +fn pack_for_agency_v2(message: &A2AMessage, agency_did: &str) -> VcxResult> { let agent_vk = settings::get_config_value(settings::CONFIG_REMOTE_TO_SDK_VERKEY)?; let my_vk = settings::get_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY)?; - let message = serde_json::to_string(&message).or(Err(error::SERIALIZATION_ERROR.code_num))?; - let receiver_keys = ::serde_json::to_string(&vec![&agent_vk]).or(Err(error::SERIALIZATION_ERROR.code_num))?; + let message = ::serde_json::to_string(&message) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize A2A message: {}", err)))?; + + let receiver_keys = ::serde_json::to_string(&vec![&agent_vk]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize receiver keys: {}", err)))?; let message = crypto::pack_message(Some(&my_vk), &receiver_keys, message.as_bytes())?; prepare_forward_message(message, agency_did) } -fn parse_response_from_agency(response: &Vec) -> Result, u32> { +fn parse_response_from_agency(response: &Vec) -> VcxResult> { match settings::get_protocol_type() { settings::ProtocolTypes::V1 => parse_response_from_agency_v1(response), settings::ProtocolTypes::V2 => parse_response_from_agency_v2(response) } } -fn parse_response_from_agency_v1(response: &Vec) -> Result, u32> { +fn parse_response_from_agency_v1(response: &Vec) -> VcxResult> { let verkey = settings::get_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY)?; let (_, data) = crypto::parse_msg(&verkey, &response)?; let bundle: Bundled> = bundle_from_u8(data)?; bundle.bundled .iter() .map(|msg| rmp_serde::from_slice(msg) - .map_err(|err| error::INVALID_JSON.code_num)) - .collect::, u32>>() + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize response: {}", err)))) + .collect::>>() } -fn parse_response_from_agency_v2(response: &Vec) -> Result, u32> { +fn parse_response_from_agency_v2(response: &Vec) -> VcxResult> { let unpacked_msg = crypto::unpack_message(&response[..])?; let message: Value = ::serde_json::from_slice(unpacked_msg.as_slice()) - .or(Err(error::INVALID_JSON.code_num))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize response: {}", err)))?; - let message = message["message"].as_str().ok_or(error::INVALID_JSON.code_num)?; + let message = message["message"].as_str() + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidJson, "Cannot find `message` field on response"))?; let message: A2AMessage = serde_json::from_str(message) - .map_err(|ec| { error::INVALID_JSON.code_num })?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize A2A message: {}", err)))?; + Ok(vec![message]) } @@ -858,21 +782,21 @@ impl Bundled { } } - pub fn encode(&self) -> Result, u32> where T: serde::Serialize { + pub fn encode(&self) -> VcxResult> where T: serde::Serialize { rmp_serde::to_vec_named(self) .map_err(|err| { error!("Could not convert bundle to messagepack: {}", err); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Could not encode bundle: {}", err)) }) } } -pub fn try_i8_bundle(data: Vec) -> Result>, u32> { +pub fn try_i8_bundle(data: Vec) -> VcxResult>> { let bundle: Bundled> = rmp_serde::from_slice(&data[..]) .map_err(|err| { warn!("could not deserialize bundle with i8, will try u8"); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::InvalidMessagePack, "Could not deserialize bundle with i8") })?; let mut new_bundle: Bundled> = Bundled { bundled: Vec::new() }; @@ -892,16 +816,16 @@ pub fn to_i8(bytes: &Vec) -> Vec { bytes.iter().map(|i| *i as i8).collect() } -pub fn bundle_from_u8(data: Vec) -> Result>, u32> { +pub fn bundle_from_u8(data: Vec) -> VcxResult>> { try_i8_bundle(data.clone()) .or_else(|_| rmp_serde::from_slice::>>(&data[..])) .map_err(|err| { error!("could not deserialize bundle with i8 or u8: {}", err); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::InvalidMessagePack, "Could not deserialize bundle with i8 or u8") }) } -fn prepare_forward_message(message: Vec, did: &str) -> Result, u32> { +fn prepare_forward_message(message: Vec, did: &str) -> VcxResult> { let agency_vk = settings::get_config_value(settings::CONFIG_AGENCY_VERKEY)?; let message = Forward::new(did.to_string(), message); @@ -912,33 +836,38 @@ fn prepare_forward_message(message: Vec, did: &str) -> Result, u32> } } -fn prepare_forward_message_for_agency_v1(message: &Forward, agency_vk: &str) -> Result, u32> { - let message = rmp_serde::to_vec_named(message).or(Err(error::UNKNOWN_ERROR.code_num))?; +fn prepare_forward_message_for_agency_v1(message: &Forward, agency_vk: &str) -> VcxResult> { + let message = rmp_serde::to_vec_named(message) + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, format!("Cannot serialize Forward message: {}", err)))?; let message = Bundled::create(message).encode()?; crypto::prep_anonymous_msg(agency_vk, &message[..]) } -fn prepare_forward_message_for_agency_v2(message: &Forward, agency_vk: &str) -> Result, u32> { - let message = serde_json::to_string(message).or(Err(error::SERIALIZATION_ERROR.code_num))?; - let receiver_keys = serde_json::to_string(&vec![agency_vk]).or(Err(error::SERIALIZATION_ERROR.code_num))?; +fn prepare_forward_message_for_agency_v2(message: &Forward, agency_vk: &str) -> VcxResult> { + let message = serde_json::to_string(message) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize Forward message: {}", err)))?; + + let receiver_keys = serde_json::to_string(&vec![agency_vk]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize receiver keys: {}", err)))?; + crypto::pack_message(None, &receiver_keys, message.as_bytes()) } -pub fn prepare_message_for_agent(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result, u32> { +pub fn prepare_message_for_agent(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> VcxResult> { match settings::get_protocol_type() { settings::ProtocolTypes::V1 => prepare_message_for_agent_v1(messages, pw_vk, agent_did, agent_vk), settings::ProtocolTypes::V2 => prepare_message_for_agent_v2(messages, pw_vk, agent_did, agent_vk) } } -fn prepare_message_for_agent_v1(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result, u32> { +fn prepare_message_for_agent_v1(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> VcxResult> { let message = messages .iter() .map(|msg| rmp_serde::to_vec_named(msg)) .collect::, _>>() .map(|msgs| Bundled { bundled: msgs }) .and_then(|bundle| rmp_serde::to_vec_named(&bundle)) - .or(Err(error::SERIALIZATION_ERROR.code_num))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize A2A message: {}", err)))?; let message = crypto::prep_msg(&pw_vk, agent_vk, &message[..])?; @@ -950,10 +879,15 @@ fn prepare_message_for_agent_v1(messages: Vec, pw_vk: &str, agent_di bundle_for_agency_v1(&A2AMessage::Version1(A2AMessageV1::Forward(message)), &to_did) } -fn prepare_message_for_agent_v2(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result, u32> { - let message = messages.get(0).ok_or(error::SERIALIZATION_ERROR.code_num)?; - let message = serde_json::to_string(message).or(Err(error::SERIALIZATION_ERROR.code_num))?; - let receiver_keys = serde_json::to_string(&vec![&agent_vk]).or(Err(error::SERIALIZATION_ERROR.code_num))?; +fn prepare_message_for_agent_v2(messages: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> VcxResult> { + let message = messages.get(0) + .ok_or(VcxError::from_msg(VcxErrorKind::SerializationError, "Cannot get message"))?; + + let message = serde_json::to_string(message) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize A2A message: {}", err)))?; + + let receiver_keys = serde_json::to_string(&vec![&agent_vk]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot receiver keys: {}", err)))?; let message = crypto::pack_message(Some(pw_vk), &receiver_keys, message.as_bytes())?; @@ -970,25 +904,25 @@ pub trait GeneralMessage { //todo: deserialize_message - fn to(&mut self, to_did: &str) -> Result<&mut Self, u32> { + fn to(&mut self, to_did: &str) -> VcxResult<&mut Self> { validation::validate_did(to_did)?; self.set_to_did(to_did.to_string()); Ok(self) } - fn to_vk(&mut self, to_vk: &str) -> Result<&mut Self, u32> { + fn to_vk(&mut self, to_vk: &str) -> VcxResult<&mut Self> { validation::validate_verkey(to_vk)?; self.set_to_vk(to_vk.to_string()); Ok(self) } - fn agent_did(&mut self, did: &str) -> Result<&mut Self, u32> { + fn agent_did(&mut self, did: &str) -> VcxResult<&mut Self> { validation::validate_did(did)?; self.set_agent_did(did.to_string()); Ok(self) } - fn agent_vk(&mut self, to_vk: &str) -> Result<&mut Self, u32> { + fn agent_vk(&mut self, to_vk: &str) -> VcxResult<&mut Self> { validation::validate_verkey(to_vk)?; self.set_agent_vk(to_vk.to_string()); Ok(self) @@ -999,7 +933,29 @@ pub trait GeneralMessage { fn set_agent_did(&mut self, did: String); fn set_agent_vk(&mut self, vk: String); - fn prepare_request(&mut self) -> Result, u32>; + fn prepare_request(&mut self) -> VcxResult>; +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ObjectWithVersion<'a, T> { + pub version: &'a str, + pub data: T +} + +impl<'a, 'de, T> ObjectWithVersion<'a, T> where T: ::serde::Serialize + ::serde::de::DeserializeOwned { + pub fn new(version: &'a str, data: T) -> ObjectWithVersion<'a, T> { + ObjectWithVersion { version, data } + } + + pub fn serialize(&self) -> VcxResult { + ::serde_json::to_string(self) + .to_vcx(VcxErrorKind::InvalidState, "Cannot serialize object") + } + + pub fn deserialize(data: &str) -> VcxResult> where T: ::serde::de::DeserializeOwned { + ::serde_json::from_str(data) + .to_vcx(VcxErrorKind::InvalidJson, "Cannot deserialize object") + } } pub fn create_keys() -> CreateKeyBuilder { CreateKeyBuilder::create() } diff --git a/vcx/libvcx/src/messages/payload.rs b/vcx/libvcx/src/messages/payload.rs index d1e0cdedf3..ad8f7db32b 100644 --- a/vcx/libvcx/src/messages/payload.rs +++ b/vcx/libvcx/src/messages/payload.rs @@ -1,8 +1,8 @@ use messages::message_type::*; use messages::to_u8; use settings::{ProtocolTypes, get_protocol_type}; -use utils::error; use utils::libindy::crypto; +use error::prelude::*; use std::collections::HashMap; @@ -37,7 +37,7 @@ impl Payloads { // this will become a CommonError, because multiple types (Connection/Issuer Credential) use this function // Possibly this function moves out of this file. // On second thought, this should stick as a ConnectionError. - pub fn encrypt(my_vk: &str, their_vk: &str, data: &str, msg_type: PayloadKinds, thread: Option) -> Result, u32> { + pub fn encrypt(my_vk: &str, their_vk: &str, data: &str, msg_type: PayloadKinds, thread: Option) -> VcxResult> { match ProtocolTypes::from(get_protocol_type()) { ProtocolTypes::V1 => { let payload = PayloadV1 { @@ -48,14 +48,14 @@ impl Payloads { let bytes = rmp_serde::to_vec_named(&payload) .map_err(|err| { error!("could not encode create_keys msg: {}", err); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Cannot encrypt payload: {}", err)) })?; trace!("Sending payload: {:?}", bytes); crypto::prep_msg(&my_vk, &their_vk, &bytes) } ProtocolTypes::V2 => { - let thread = thread.ok_or(error::INVALID_CONNECTION_HANDLE.code_num)?; + let thread = thread.ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "Thread info not found"))?; let payload = PayloadV2 { type_: PayloadTypes::build_v2(msg_type), @@ -67,10 +67,11 @@ impl Payloads { let message = ::serde_json::to_string(&payload) .map_err(|err| { error!("could not serialize create_keys msg: {}", err); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize payload: {}", err)) })?; - let receiver_keys = ::serde_json::to_string(&vec![&their_vk]).or(Err(error::SERIALIZATION_ERROR.code_num))?; + let receiver_keys = ::serde_json::to_string(&vec![&their_vk]) + .map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Cannot serialize receiver keys: {}", err)))?; trace!("Sending payload: {:?}", message.as_bytes()); crypto::pack_message(Some(my_vk), &receiver_keys, message.as_bytes()) @@ -78,16 +79,13 @@ impl Payloads { } } - pub fn decrypt(my_vk: &str, payload: &Vec) -> Result<(String, Option), u32> { + pub fn decrypt(my_vk: &str, payload: &Vec) -> VcxResult<(String, Option)> { match ProtocolTypes::from(get_protocol_type()) { ProtocolTypes::V1 => { let (_, data) = crypto::parse_msg(&my_vk, &to_u8(payload))?; let my_payload: PayloadV1 = rmp_serde::from_slice(&data[..]) - .map_err(|err| { - error!("could not deserialize bundle with i8 or u8: {}", err); - error::INVALID_MSGPACK.code_num - })?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidMessagePack, format!("Cannot decrypt payload: {}", err)))?; Ok((my_payload.msg, None)) } ProtocolTypes::V2 => { @@ -96,18 +94,19 @@ impl Payloads { } } - pub fn decrypt_payload_v2(my_vk: &str, payload: &Vec) -> Result<(String, Option), u32> { + pub fn decrypt_payload_v2(my_vk: &str, payload: &Vec) -> VcxResult<(String, Option)> { let unpacked_msg = crypto::unpack_message(&to_u8(payload))?; let message: ::serde_json::Value = ::serde_json::from_slice(unpacked_msg.as_slice()) - .or(Err(error::INVALID_JSON.code_num))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize payload: {}", err)))?; - let message = message["message"].as_str().ok_or(error::INVALID_JSON.code_num)?.to_string(); + let message = message["message"].as_str() + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidJson, "Cannot find `message` field"))?.to_string(); let mut my_payload: PayloadV2 = serde_json::from_str(&message) .map_err(|err| { error!("could not deserialize bundle with i8 or u8: {}", err); - error::INVALID_MSGPACK.code_num + VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize payload: {}", err)) })?; if my_payload.thread.thid.is_none() { diff --git a/vcx/libvcx/src/messages/proofs/proof_message.rs b/vcx/libvcx/src/messages/proofs/proof_message.rs index 58ffd1ab50..787eeebeb1 100644 --- a/vcx/libvcx/src/messages/proofs/proof_message.rs +++ b/vcx/libvcx/src/messages/proofs/proof_message.rs @@ -1,17 +1,9 @@ -extern crate serde_json; - -use utils::{ error }; +use serde_json; use serde_json::Value; -use error::proof::ProofError; - -static ISSUER_DID: &'static str = "issuer_did"; -static SEQUENCE_NUMBER: &'static str = "schema_seq_no"; -static PROVER_DID: &'static str = "prover_did"; -static MSG_FROM_API: &str = r#"{"proofs":{"claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4":{"proof":{"primary_proof":{"eq_proof":{"revealed_attrs":{"sex":"5944657099558967239210949258394887428692050081607692519917050011144233115103","name":"1139481716457488690172217916278103335"},"a_prime":"55115757663642844902979276276581544287881791112969892277372135316353511833640150801244335663890109536491278379177551666081054765286807563008348637104046950934828407012194403360724040287698135607556244297972578864339500981366412262454282194811242239615009347165118318516694216754501345324782597475927199400880006212632553233049354866295429520527445980181939247828351677971991914388778860092824318440481574181300185829423762990910739241691289976584754979812272223819007422499654272590946235912914032826994670588466080422906806402660885408376207875827950805200378568062518210110828954480363081643567615791016011737856977","e":"34976147138641338975844073241645969211530343885520088294714132974884138611036204288689212378023649179372520412699253155486970203797562324","v":"961473607552945346906354315658276499450491951690969023699851664262072769313929148332129868528140265952852653009499943891795293148107502144091334703992581737220352761140064276811372868396353572957613845323343723271098601244774874235526135299483412285009916812621185291842845156342501611029106982811773616231232684804116984093651972537804480090649736612551759833591251845595059217608938213987633789344584340351801507541774726753840600143685051258161251666953243698589585559347435011414292427590918153421953579895479604685390401357681887618798200391305919594609949167659780330698000168295871428737686822637913218269005987492318466661186509308179489615192663542904993253626728197630057096161118638090776180812895097232529119979970798938360220605280817954648588493778338816318524451785027916181454650102696493927306340658666852294316562458212054696739343800993703515542777264448535624584845146378512183572107830260813929222999","m":{},"m1":"75548120024969192086664289521241751069844239013520403238642886571169851979005373784309432586593371476370934469326730539754613694936161784687213609047455188306625204249706249661640538349287762196100659095340756990269587317065862046598569445591945049204366911309949910119711238973099702616527117177036784698661","m2":"287944186286321709724396773443214682376883853676549188669693055373059354657799325692443906346632814001611911026063358134413175852024773765930829079850890920811398176944587192618"},"ge_proofs":[]},"non_revoc_proof":null},"schema_seq_no":103,"issuer_did":"V4SGRU86Z58d6TV7PBUe6f"}},"aggregated_proof":{"c_hash":"63330487197040957750863022608534150304998351350639315143102570772502292901825","c_list":[[1,180,153,212,162,132,5,189,14,181,140,112,236,109,182,76,91,6,161,215,62,207,205,135,86,211,49,197,215,198,104,201,14,22,48,6,112,170,31,191,110,118,121,15,62,114,126,249,221,107,114,161,163,234,19,233,150,236,182,217,195,6,218,217,193,6,94,160,33,23,103,147,109,221,81,38,138,20,225,141,68,37,142,10,225,79,164,119,168,250,188,186,47,229,165,8,237,230,14,35,53,176,97,28,82,105,87,210,117,16,154,222,66,11,96,172,90,13,239,190,29,71,11,88,53,36,219,139,67,21,136,58,161,164,97,106,56,230,55,157,59,35,187,235,154,194,111,93,168,135,67,15,97,136,38,169,87,142,32,255,50,247,111,83,44,88,251,99,6,226,182,170,146,229,118,164,118,228,235,51,137,168,135,50,1,14,1,201,72,175,102,241,149,117,88,83,84,37,205,130,26,155,124,158,211,89,112,33,46,24,94,93,202,8,127,172,214,178,6,156,79,188,132,223,239,127,200,158,95,247,139,101,51,162,168,175,74,1,67,201,94,108,192,14,130,109,217,248,193,10,142,37,95,231,227,251,209]]},"requested_proof":{"revealed_attrs":{"attr2_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","male","5944657099558967239210949258394887428692050081607692519917050011144233115103"],"attr1_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","Alex","1139481716457488690172217916278103335"]},"unrevealed_attrs":{},"self_attested_attrs":{},"predicates":{}},"remoteDid":"KP8AaEBc368CMK1PqZaEzX","userPairwiseDid":"PofTCeegEXT7S2aAePhM6a"}"#; - +use error::prelude::*; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub struct ProofMessage{ +pub struct ProofMessage { version: Option, to_did: Option, from_did: Option, @@ -38,26 +30,21 @@ impl ProofMessage { } } - pub fn to_string(&self) -> Result { - serde_json::to_string(&self).map_err(|err| { - error!("{} with: {}", error::INVALID_PROOF.message, err); - error::INVALID_PROOF.code_num - }) + pub fn to_string(&self) -> VcxResult { + serde_json::to_string(&self) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidProof, format!("Cannot serialize proof: {}", err))) } - pub fn from_str(payload:&str) -> Result { + pub fn from_str(payload: &str) -> VcxResult { serde_json::from_str(payload) - .map_err(|err| { - error!("{} with serde error: {}",error::INVALID_PROOF.message, err); - error::INVALID_PROOF.code_num - }) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidProof, format!("Cannot deserialize proof: {}", err))) } - pub fn get_credential_info(&self) -> Result, ProofError> { + pub fn get_credential_info(&self) -> VcxResult> { let mut rtn = Vec::new(); let credentials: Value = serde_json::from_str(&self.libindy_proof) - .or(Err(ProofError::InvalidJson()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize liibndy proof: {}", err)))?; if let Value::Array(ref identifiers) = credentials["identifiers"] { for identifier in identifiers { @@ -76,23 +63,24 @@ impl ProofMessage { timestamp, } ); - } else { return Err(ProofError::InvalidCredData()) } + } else { return Err(VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, "Cannot get identifiers")); } } } Ok(rtn) } - } #[cfg(test)] pub mod tests { use super::*; use ::utils::constants::{SCHEMA_ID, CRED_DEF_ID, REV_REG_ID}; + static TEMP_REQUESTER_DID: &'static str = "GxtnGN6ypZYgEqcftSQFnC"; static MSG_FROM_API: &str = r#"{"proofs":{"claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4":{"proof":{"primary_proof":{"eq_proof":{"revealed_attrs":{"sex":"5944657099558967239210949258394887428692050081607692519917050011144233115103","name":"1139481716457488690172217916278103335"},"a_prime":"55115757663642844902979276276581544287881791112969892277372135316353511833640150801244335663890109536491278379177551666081054765286807563008348637104046950934828407012194403360724040287698135607556244297972578864339500981366412262454282194811242239615009347165118318516694216754501345324782597475927199400880006212632553233049354866295429520527445980181939247828351677971991914388778860092824318440481574181300185829423762990910739241691289976584754979812272223819007422499654272590946235912914032826994670588466080422906806402660885408376207875827950805200378568062518210110828954480363081643567615791016011737856977","e":"34976147138641338975844073241645969211530343885520088294714132974884138611036204288689212378023649179372520412699253155486970203797562324","v":"961473607552945346906354315658276499450491951690969023699851664262072769313929148332129868528140265952852653009499943891795293148107502144091334703992581737220352761140064276811372868396353572957613845323343723271098601244774874235526135299483412285009916812621185291842845156342501611029106982811773616231232684804116984093651972537804480090649736612551759833591251845595059217608938213987633789344584340351801507541774726753840600143685051258161251666953243698589585559347435011414292427590918153421953579895479604685390401357681887618798200391305919594609949167659780330698000168295871428737686822637913218269005987492318466661186509308179489615192663542904993253626728197630057096161118638090776180812895097232529119979970798938360220605280817954648588493778338816318524451785027916181454650102696493927306340658666852294316562458212054696739343800993703515542777264448535624584845146378512183572107830260813929222999","m":{},"m1":"75548120024969192086664289521241751069844239013520403238642886571169851979005373784309432586593371476370934469326730539754613694936161784687213609047455188306625204249706249661640538349287762196100659095340756990269587317065862046598569445591945049204366911309949910119711238973099702616527117177036784698661","m2":"287944186286321709724396773443214682376883853676549188669693055373059354657799325692443906346632814001611911026063358134413175852024773765930829079850890920811398176944587192618"},"ge_proofs":[{"u":{"1":"1","0":"0","3":"3","2":"4"},"r":{"1":"1","0":"2","DELTA":"3","3":"4","2":"5"},"mj":"6","alpha":"7","t":{"1":"8","3":"3","0":"2","DELTA":"1","2":"2"},"predicate":{"attr_name":"age","p_type":"GE","value":18,"schema_seq_no":14,"issuer_did":"33UDR9R7fjwELRvH9JT6HH"}}]},"non_revoc_proof":null},"schema_seq_no":103,"issuer_did":"V4SGRU86Z58d6TV7PBUe6f"}},"aggregated_proof":{"c_hash":"63330487197040957750863022608534150304998351350639315143102570772502292901825","c_list":[[1,180,153,212,162,132,5,189,14,181,140,112,236,109,182,76,91,6,161,215,62,207,205,135,86,211,49,197,215,198,104,201,14,22,48,6,112,170,31,191,110,118,121,15,62,114,126,249,221,107,114,161,163,234,19,233,150,236,182,217,195,6,218,217,193,6,94,160,33,23,103,147,109,221,81,38,138,20,225,141,68,37,142,10,225,79,164,119,168,250,188,186,47,229,165,8,237,230,14,35,53,176,97,28,82,105,87,210,117,16,154,222,66,11,96,172,90,13,239,190,29,71,11,88,53,36,219,139,67,21,136,58,161,164,97,106,56,230,55,157,59,35,187,235,154,194,111,93,168,135,67,15,97,136,38,169,87,142,32,255,50,247,111,83,44,88,251,99,6,226,182,170,146,229,118,164,118,228,235,51,137,168,135,50,1,14,1,201,72,175,102,241,149,117,88,83,84,37,205,130,26,155,124,158,211,89,112,33,46,24,94,93,202,8,127,172,214,178,6,156,79,188,132,223,239,127,200,158,95,247,139,101,51,162,168,175,74,1,67,201,94,108,192,14,130,109,217,248,193,10,142,37,95,231,227,251,209]]},"requested_proof":{"revealed_attrs":{"attr2_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","male","5944657099558967239210949258394887428692050081607692519917050011144233115103"],"attr1_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","Alex","1139481716457488690172217916278103335"]},"unrevealed_attrs":{},"self_attested_attrs":{"self_attr":"self_value"},"predicates":{"predicate_id":"claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4"}},"remoteDid":"KP8AaEBc368CMK1PqZaEzX","userPairwiseDid":"PofTCeegEXT7S2aAePhM6a"}"#; static TEST_ATTRS: &str = r#"[{"schema_seq_no":14,"issuer_did":"33UDR9R7fjwELRvH9JT6HH","credential_uuid":"claim::f33cc7c8-924f-4541-aeff-29a9aed9c46b","proof_attrs":[{"name":"state","value":"UT","revealed":true}]},{"schema_seq_no":15,"issuer_did":"4fUDR9R7fjwELRvH9JT6HH","credential_uuid":"claim::f22cc7c8-924f-4541-aeff-29a9aed9c46b","proof_attrs":[{"name":"state","value":"UT","revealed":true}]}]"#; - pub fn create_default_proof()-> ProofMessage { + + pub fn create_default_proof() -> ProofMessage { let mut proof = ProofMessage::new(); proof.libindy_proof = ::utils::constants::INDY_PROOF_JSON.to_string(); proof.from_did = Some(::settings::get_config_value(::settings::CONFIG_INSTITUTION_DID).unwrap()); @@ -100,18 +88,18 @@ pub mod tests { } #[test] - fn test_proof_struct(){ + fn test_proof_struct() { init!("true"); let offer = create_default_proof(); assert_eq!(offer.from_did, Some(::settings::get_config_value(::settings::CONFIG_INSTITUTION_DID).unwrap())); } #[test] - fn test_serialize_deserialize(){ + fn test_serialize_deserialize() { let proof = create_default_proof(); let serialized = proof.to_string().unwrap(); let proof2 = ProofMessage::from_str(&serialized).unwrap(); - assert_eq!(proof,proof2); + assert_eq!(proof, proof2); } #[test] @@ -119,22 +107,22 @@ pub mod tests { init!("true"); let mut proof = ProofMessage::new(); proof.libindy_proof = "".to_string(); - assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidJson())); + assert_eq!(proof.get_credential_info().unwrap_err().kind(), VcxErrorKind::InvalidJson); proof.libindy_proof = "{}".to_string(); - assert_eq!(proof.get_credential_info(), Ok(Vec::new())); + assert_eq!(proof.get_credential_info().unwrap(), Vec::new()); proof.libindy_proof = json!({"identifiers": []}).to_string(); - assert_eq!(proof.get_credential_info(), Ok(Vec::new())); + assert_eq!(proof.get_credential_info().unwrap(), Vec::new()); proof.libindy_proof = json!({"identifiers": [{}]}).to_string(); - assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidCredData())); + assert_eq!(proof.get_credential_info().unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); proof.libindy_proof = json!({"identifiers": [{ "schema_id": null, "cred_def_id": null, }]}).to_string(); - assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidCredData())); + assert_eq!(proof.get_credential_info().unwrap_err().kind(), VcxErrorKind::InvalidProofCredentialData); proof.libindy_proof = json!({"identifiers": [{ "schema_id": SCHEMA_ID, diff --git a/vcx/libvcx/src/messages/proofs/proof_request.rs b/vcx/libvcx/src/messages/proofs/proof_request.rs index 526228d27e..9ab6299140 100644 --- a/vcx/libvcx/src/messages/proofs/proof_request.rs +++ b/vcx/libvcx/src/messages/proofs/proof_request.rs @@ -1,15 +1,13 @@ -extern crate rust_base58; -extern crate serde_json; +use serde_json; use std::collections::HashMap; use std::vec::Vec; -use utils::error; + use messages::validation; +use error::prelude::*; static PROOF_REQUEST: &str = "PROOF_REQUEST"; static PROOF_DATA: &str = "proof_request_data"; -static REQUESTED_ATTRS: &str = "requested_attributes"; -static REQUESTED_PREDICATES: &str = "requested_predicates"; #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, PartialOrd)] struct ProofType { @@ -67,7 +65,7 @@ pub struct NonRevokedInterval { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub struct ProofRequestData{ +pub struct ProofRequestData { nonce: String, name: String, #[serde(rename = "version")] @@ -78,14 +76,12 @@ pub struct ProofRequestData{ } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub struct ProofRequestMessage{ +pub struct ProofRequestMessage { #[serde(rename = "@type")] type_header: ProofType, #[serde(rename = "@topic")] topic: ProofTopic, pub proof_request_data: ProofRequestData, - #[serde(skip_serializing, default)] - validate_rc: u32, pub msg_ref_id: Option, from_timestamp: Option, to_timestamp: Option, @@ -115,11 +111,10 @@ impl ProofRequestMessage { nonce: String::new(), name: String::new(), data_version: String::new(), - requested_attributes:HashMap::new(), + requested_attributes: HashMap::new(), requested_predicates: HashMap::new(), non_revoked: None }, - validate_rc: 0, msg_ref_id: None, from_timestamp: None, to_timestamp: None, @@ -127,55 +122,45 @@ impl ProofRequestMessage { } } - pub fn type_version(&mut self, version: &str) -> &mut Self { + pub fn type_version(&mut self, version: &str) -> VcxResult<&mut Self> { self.type_header.type_version = String::from(version); - self + Ok(self) } - pub fn tid(&mut self, tid: u32) -> &mut Self { + pub fn tid(&mut self, tid: u32) -> VcxResult<&mut Self> { self.topic.tid = tid; - self + Ok(self) } - pub fn mid(&mut self, mid: u32) -> &mut Self { + pub fn mid(&mut self, mid: u32) -> VcxResult<&mut Self> { self.topic.mid = mid; - self + Ok(self) } - pub fn nonce(&mut self, nonce: &str) -> &mut Self { - match validation::validate_nonce(nonce) { - Ok(x) => { - self.proof_request_data.nonce = x; - self - }, - Err(x) => { - self.validate_rc = x; - self - }, - } + pub fn nonce(&mut self, nonce: &str) -> VcxResult<&mut Self> { + let nonce = validation::validate_nonce(nonce)?; + self.proof_request_data.nonce = nonce; + Ok(self) } - pub fn proof_name(&mut self, name: &str) -> &mut Self { + pub fn proof_name(&mut self, name: &str) -> VcxResult<&mut Self> { self.proof_request_data.name = String::from(name); - self + Ok(self) } - pub fn proof_data_version(&mut self, version: &str) -> &mut Self { + pub fn proof_data_version(&mut self, version: &str) -> VcxResult<&mut Self> { self.proof_request_data.data_version = String::from(version); - self + Ok(self) } - pub fn requested_attrs(&mut self, attrs: &str) -> &mut Self { + pub fn requested_attrs(&mut self, attrs: &str) -> VcxResult<&mut Self> { let mut check_req_attrs: HashMap = HashMap::new(); - let proof_attrs:Vec = match serde_json::from_str(attrs) { - Ok(a) => a, - Err(e) => { - debug!("Cannot parse attributes: {}", e); - self.validate_rc = error::INVALID_JSON.code_num; - return self - } - }; + let proof_attrs: Vec = serde_json::from_str(attrs) + .map_err(|err| { + debug!("Cannot parse attributes: {}", err); + VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot parse attributes: {}", err)) + })?; let mut index = 1; for attr in proof_attrs { @@ -184,22 +169,19 @@ impl ProofRequestMessage { } else { check_req_attrs.insert(attr.name.clone(), attr); } - index= index + 1; + index = index + 1; } self.proof_request_data.requested_attributes = check_req_attrs; - self + Ok(self) } - pub fn requested_predicates(&mut self, predicates: &str) -> &mut Self { + pub fn requested_predicates(&mut self, predicates: &str) -> VcxResult<&mut Self> { let mut check_predicates: HashMap = HashMap::new(); - let attr_values: Vec = match serde_json::from_str(predicates) { - Ok(a) => a, - Err(e) => { - debug!("Cannot parse predicates: {}", e); - self.validate_rc = error::INVALID_JSON.code_num; - return self - }, - }; + let attr_values: Vec = serde_json::from_str(predicates) + .map_err(|err| { + debug!("Cannot parse predicates: {}", err); + VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot parse predicates: {}", err)) + })?; let mut index = 1; for attr in attr_values { @@ -212,39 +194,31 @@ impl ProofRequestMessage { } self.proof_request_data.requested_predicates = check_predicates; - self + Ok(self) } - pub fn from_timestamp(&mut self, from: Option) -> &mut Self { + pub fn from_timestamp(&mut self, from: Option) -> VcxResult<&mut Self> { self.from_timestamp = from; - self + Ok(self) } - pub fn to_timestamp(&mut self, to: Option) -> &mut Self { + pub fn to_timestamp(&mut self, to: Option) -> VcxResult<&mut Self> { self.to_timestamp = to; - self + Ok(self) } - pub fn serialize_message(&mut self) -> Result { - if self.validate_rc != error::SUCCESS.code_num { - return Err(self.validate_rc) - } - - match serde_json::to_string(self) { - Ok(x) => Ok(x), - Err(_) => Err(error::INVALID_JSON.code_num) - } + pub fn serialize_message(&mut self) -> VcxResult { + serde_json::to_string(self) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof request: {}", err))) } pub fn get_proof_request_data(&self) -> String { json!(self)[PROOF_DATA].to_string() } - pub fn to_string(&self) -> Result { - match serde_json::to_string(&self){ - Ok(s) => Ok(s), - Err(_) => Err(error::INVALID_JSON.code_num), - } + pub fn to_string(&self) -> VcxResult { + serde_json::to_string(&self) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof request: {}", err))) } } @@ -252,7 +226,7 @@ impl ProofRequestMessage { #[cfg(test)] mod tests { use super::*; - use messages::{proof_request}; + use messages::proof_request; use utils::constants::{REQUESTED_ATTRS, REQUESTED_PREDICATES}; #[test] @@ -281,16 +255,16 @@ mod tests { let mid = 98; let mut request = proof_request() - .type_version(version) - .tid(tid) - .mid(mid) - .nonce(nonce) - .proof_name(data_name) - .proof_data_version(data_version) - .requested_attrs(REQUESTED_ATTRS) - .requested_predicates(REQUESTED_PREDICATES) - .to_timestamp(Some(100)) - .from_timestamp(Some(1)) + .type_version(version).unwrap() + .tid(tid).unwrap() + .mid(mid).unwrap() + .nonce(nonce).unwrap() + .proof_name(data_name).unwrap() + .proof_data_version(data_version).unwrap() + .requested_attrs(REQUESTED_ATTRS).unwrap() + .requested_predicates(REQUESTED_PREDICATES).unwrap() + .to_timestamp(Some(100)).unwrap() + .from_timestamp(Some(1)).unwrap() .clone(); let serialized_msg = request.serialize_message().unwrap(); @@ -312,7 +286,7 @@ mod tests { check_req_attrs.insert("age".to_string(), attr_info1); check_req_attrs.insert("name".to_string(), attr_info2); - let request = proof_request().requested_attrs(REQUESTED_ATTRS).clone(); + let request = proof_request().requested_attrs(REQUESTED_ATTRS).unwrap().clone(); assert_eq!(request.proof_request_data.requested_attributes, check_req_attrs); } @@ -322,7 +296,7 @@ mod tests { let attr_info1: PredicateInfo = serde_json::from_str(r#"{ "name":"age","p_type":"GE","p_value":22, "restrictions":[ { "schema_id": "6XFh8yBzrpJQmNyZzgoTqB:2:schema_name:0.0.11", "schema_name":"Faber Student Info", "schema_version":"1.0", "schema_issuer_did":"6XFh8yBzrpJQmNyZzgoTqB", "issuer_did":"8XFh8yBzrpJQmNyZzgoTqB", "cred_def_id": "8XFh8yBzrpJQmNyZzgoTqB:3:CL:1766" }, { "schema_id": "5XFh8yBzrpJQmNyZzgoTqB:2:schema_name:0.0.11", "schema_name":"BYU Student Info", "schema_version":"1.0", "schema_issuer_did":"5XFh8yBzrpJQmNyZzgoTqB", "issuer_did":"66Fh8yBzrpJQmNyZzgoTqB", "cred_def_id": "66Fh8yBzrpJQmNyZzgoTqB:3:CL:1766" } ] }"#).unwrap(); check_predicates.insert("age".to_string(), attr_info1); - let request = proof_request().requested_predicates(REQUESTED_PREDICATES).clone(); + let request = proof_request().requested_predicates(REQUESTED_PREDICATES).unwrap().clone(); assert_eq!(request.proof_request_data.requested_predicates, check_predicates); } diff --git a/vcx/libvcx/src/messages/send_message.rs b/vcx/libvcx/src/messages/send_message.rs index b40f7fd843..e5cb555fdf 100644 --- a/vcx/libvcx/src/messages/send_message.rs +++ b/vcx/libvcx/src/messages/send_message.rs @@ -4,8 +4,9 @@ use api::VcxStateType; use messages::*; use messages::message_type::MessageTypes; use messages::payload::{Payloads, PayloadKinds, Thread}; -use utils::{httpclient, error}; +use utils::httpclient; use utils::uuid::uuid; +use error::prelude::*; #[derive(Debug)] pub struct SendMessageBuilder { @@ -41,46 +42,47 @@ impl SendMessageBuilder { } } - pub fn msg_type(&mut self, msg: &RemoteMessageType) -> Result<&mut Self, u32> { + pub fn msg_type(&mut self, msg: &RemoteMessageType) -> VcxResult<&mut Self> { //Todo: validate msg?? self.mtype = msg.clone(); Ok(self) } - pub fn uid(&mut self, uid: Option<&str>) -> Result<&mut Self, u32> { + pub fn uid(&mut self, uid: Option<&str>) -> VcxResult<&mut Self> { //Todo: validate msg_uid?? self.uid = uid.map(String::from); Ok(self) } - pub fn status_code(&mut self, code: &MessageStatusCode) -> Result<&mut Self, u32> { + pub fn status_code(&mut self, code: &MessageStatusCode) -> VcxResult<&mut Self> { //Todo: validate that it can be parsed to number?? self.status_code = code.clone(); Ok(self) } - pub fn edge_agent_payload(&mut self, my_vk: &str, their_vk: &str, data: &str, payload_type: PayloadKinds, thread: Option) -> Result<&mut Self, u32> { + pub fn edge_agent_payload(&mut self, my_vk: &str, their_vk: &str, data: &str, payload_type: PayloadKinds, thread: Option) -> VcxResult<&mut Self> { //todo: is this a json value, String?? self.payload = Payloads::encrypt(my_vk, their_vk, data, payload_type, thread)?; Ok(self) } - pub fn ref_msg_id(&mut self, id: &str) -> Result<&mut Self, u32> { + + pub fn ref_msg_id(&mut self, id: &str) -> VcxResult<&mut Self> { self.ref_msg_id = Some(String::from(id)); Ok(self) } - pub fn set_title(&mut self, title: &str) -> Result<&mut Self, u32> { + pub fn set_title(&mut self, title: &str) -> VcxResult<&mut Self> { self.title = Some(title.to_string()); Ok(self) } - pub fn set_detail(&mut self, detail: &str) -> Result<&mut Self, u32> { + pub fn set_detail(&mut self, detail: &str) -> VcxResult<&mut Self> { self.detail = Some(detail.to_string()); Ok(self) } - pub fn send_secure(&mut self) -> Result { + pub fn send_secure(&mut self) -> VcxResult { trace!("SendMessage::send >>>"); if settings::test_agency_mode_enabled() { @@ -89,21 +91,21 @@ impl SendMessageBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; let result = self.parse_response(response)?; Ok(result) } - fn parse_response(&self, response: Vec) -> Result { + fn parse_response(&self, response: Vec) -> VcxResult { let mut response = parse_response_from_agency(&response)?; let index = match settings::get_protocol_type() { // TODO: THINK better settings::ProtocolTypes::V1 => { if response.len() <= 1 { - return Err(error::INVALID_HTTP_RESPONSE.code_num); + return Err(VcxError::from(VcxErrorKind::InvalidHttpResponse)); } 1 } @@ -115,7 +117,7 @@ impl SendMessageBuilder { Ok(SendResponse { uid: res.uid, uids: res.uids }), A2AMessage::Version2(A2AMessageV2::SendRemoteMessageResponse(res)) => Ok(SendResponse { uid: Some(res.id.clone()), uids: if res.sent { vec![res.id] } else { vec![] } }), - _ => return Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from(VcxErrorKind::InvalidHttpResponse)) } } } @@ -129,7 +131,7 @@ impl GeneralMessage for SendMessageBuilder { fn set_to_did(&mut self, to_did: String) { self.to_did = to_did; } fn set_to_vk(&mut self, to_vk: String) { self.to_vk = to_vk; } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { let messages = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => { @@ -175,24 +177,24 @@ pub struct SendResponse { } impl SendResponse { - pub fn get_msg_uid(&self) -> Result { + pub fn get_msg_uid(&self) -> VcxResult { self.uids .get(0) .map(|uid| uid.to_string()) - .ok_or(error::INVALID_JSON.code_num) + .ok_or(VcxError::from(VcxErrorKind::InvalidJson)) } } -pub fn send_generic_message(connection_handle: u32, msg: &str, msg_type: &str, msg_title: &str) -> Result { +pub fn send_generic_message(connection_handle: u32, msg: &str, msg_type: &str, msg_title: &str) -> VcxResult { if connection::get_state(connection_handle) != VcxStateType::VcxStateAccepted as u32 { - return Err(error::NOT_READY.code_num); + return Err(VcxError::from(VcxErrorKind::NotReady)); } - let agent_did = connection::get_agent_did(connection_handle).or(Err(error::INVALID_CONNECTION_HANDLE.code_num))?; - let agent_vk = connection::get_agent_verkey(connection_handle).or(Err(error::INVALID_CONNECTION_HANDLE.code_num))?; - let did = connection::get_pw_did(connection_handle).or(Err(error::INVALID_CONNECTION_HANDLE.code_num))?; - let vk = connection::get_pw_verkey(connection_handle).or(Err(error::INVALID_CONNECTION_HANDLE.code_num))?; - let remote_vk = connection::get_their_pw_verkey(connection_handle).or(Err(error::INVALID_CONNECTION_HANDLE.code_num))?; + let agent_did = connection::get_agent_did(connection_handle)?; + let agent_vk = connection::get_agent_verkey(connection_handle)?; + let did = connection::get_pw_did(connection_handle)?; + let vk = connection::get_pw_verkey(connection_handle)?; + let remote_vk = connection::get_their_pw_verkey(connection_handle)?; let response = send_message() @@ -205,11 +207,7 @@ pub fn send_generic_message(connection_handle: u32, msg: &str, msg_type: &str, m .set_title(&msg_title)? .set_detail(&msg_title)? .status_code(&MessageStatusCode::Accepted)? - .send_secure() - .map_err(|err| { - warn!("could not send message: {}", err); - err - })?; + .send_secure()?; let msg_uid = response.get_msg_uid()?; return Ok(msg_uid); @@ -279,7 +277,7 @@ mod tests { }; let uid = response.get_msg_uid().unwrap_err(); - assert_eq!(error::INVALID_JSON.code_num, uid); + assert_eq!(VcxErrorKind::InvalidJson, uid.kind()); } #[cfg(feature = "agency")] @@ -307,7 +305,7 @@ mod tests { match send_generic_message(handle, "this is the message", "type", "title") { Ok(x) => panic!("test shoudl fail: {}", x), - Err(x) => assert_eq!(x, error::NOT_READY.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::NotReady), }; } } diff --git a/vcx/libvcx/src/messages/update_connection.rs b/vcx/libvcx/src/messages/update_connection.rs index ee4777d30c..29505a04b5 100644 --- a/vcx/libvcx/src/messages/update_connection.rs +++ b/vcx/libvcx/src/messages/update_connection.rs @@ -1,7 +1,8 @@ use messages::*; use messages::message_type::MessageTypes; use settings; -use utils::{error, httpclient}; +use utils::httpclient; +use error::prelude::*; #[derive(Clone, Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] @@ -72,7 +73,7 @@ impl DeleteConnectionBuilder { } } - pub fn send_secure(&mut self) -> Result<(), u32> { + pub fn send_secure(&mut self) -> VcxResult<()> { trace!("DeleteConnection::send >>>"); if settings::test_agency_mode_enabled() { @@ -81,14 +82,14 @@ impl DeleteConnectionBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; let response = self.parse_response(&response)?; Ok(response) } - fn parse_response(&self, response: &Vec) -> Result<(), u32> { + fn parse_response(&self, response: &Vec) -> VcxResult<()> { trace!("parse_create_keys_response >>>"); let mut response = parse_response_from_agency(response)?; @@ -96,7 +97,7 @@ impl DeleteConnectionBuilder { match response.remove(0) { A2AMessage::Version1(A2AMessageV1::UpdateConnectionResponse(res)) => Ok(()), A2AMessage::Version2(A2AMessageV2::UpdateConnectionResponse(res)) => Ok(()), - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of UpdateConnectionResponse")) } } @@ -124,7 +125,7 @@ impl GeneralMessage for DeleteConnectionBuilder { fn set_to_did(&mut self, to_did: String) { self.to_did = to_did; } fn set_to_vk(&mut self, to_vk: String) { self.to_vk = to_vk; } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( diff --git a/vcx/libvcx/src/messages/update_message.rs b/vcx/libvcx/src/messages/update_message.rs index 49b5e06a8e..93542383eb 100644 --- a/vcx/libvcx/src/messages/update_message.rs +++ b/vcx/libvcx/src/messages/update_message.rs @@ -1,7 +1,8 @@ use settings; use messages::*; use messages::message_type::MessageTypes; -use utils::{httpclient, error}; +use utils::httpclient; +use error::prelude::*; #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] @@ -44,19 +45,19 @@ impl UpdateMessageStatusByConnectionsBuilder { } } - pub fn uids_by_conns(&mut self, uids_by_conns: Vec) -> Result<&mut Self, u32> { + pub fn uids_by_conns(&mut self, uids_by_conns: Vec) -> VcxResult<&mut Self> { //Todo: validate msg_uid?? self.uids_by_conns = uids_by_conns; Ok(self) } - pub fn status_code(&mut self, code: MessageStatusCode) -> Result<&mut Self, u32> { + pub fn status_code(&mut self, code: MessageStatusCode) -> VcxResult<&mut Self> { //Todo: validate that it can be parsed to number?? self.status_code = Some(code.clone()); Ok(self) } - pub fn send_secure(&mut self) -> Result<(), u32> { + pub fn send_secure(&mut self) -> VcxResult<()> { trace!("UpdateMessages::send >>>"); if settings::test_agency_mode_enabled() { @@ -65,12 +66,12 @@ impl UpdateMessageStatusByConnectionsBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; self.parse_response(&response) } - fn prepare_request(&mut self) -> Result, u32> { + fn prepare_request(&mut self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( @@ -98,7 +99,7 @@ impl UpdateMessageStatusByConnectionsBuilder { prepare_message_for_agency(&message, &agency_did) } - fn parse_response(&self, response: &Vec) -> Result<(), u32> { + fn parse_response(&self, response: &Vec) -> VcxResult<()> { trace!("parse_create_keys_response >>>"); let mut response = parse_response_from_agency(response)?; @@ -106,19 +107,21 @@ impl UpdateMessageStatusByConnectionsBuilder { match response.remove(0) { A2AMessage::Version1(A2AMessageV1::UpdateMessageStatusByConnectionsResponse(res)) => Ok(()), A2AMessage::Version2(A2AMessageV2::UpdateMessageStatusByConnectionsResponse(res)) => Ok(()), - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of UpdateMessageStatusByConnectionsResponse")) } } } -pub fn update_agency_messages(status_code: &str, msg_json: &str) -> Result<(), u32> { +pub fn update_agency_messages(status_code: &str, msg_json: &str) -> VcxResult<()> { trace!("update_agency_messages >>> status_code: {:?}, msg_json: {:?}", status_code, msg_json); - let status_code: MessageStatusCode = serde_json::from_str(&format!("\"{}\"", status_code)).or(Err(error::INVALID_JSON.code_num))?; + let status_code: MessageStatusCode = ::serde_json::from_str(&format!("\"{}\"", status_code)) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize MessageStatusCode: {}", err)))?; debug!("updating agency messages {} to status code: {:?}", msg_json, status_code); - let uids_by_conns: Vec = serde_json::from_str(msg_json).or(Err(error::INVALID_JSON.code_num))?; + let uids_by_conns: Vec = serde_json::from_str(msg_json) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize UIDsByConn: {}", err)))?; UpdateMessageStatusByConnectionsBuilder::create() .uids_by_conns(uids_by_conns)? diff --git a/vcx/libvcx/src/messages/update_profile.rs b/vcx/libvcx/src/messages/update_profile.rs index 0175b7bd71..d9adab3354 100644 --- a/vcx/libvcx/src/messages/update_profile.rs +++ b/vcx/libvcx/src/messages/update_profile.rs @@ -1,8 +1,9 @@ use settings; use messages::*; use messages::message_type::MessageTypes; -use utils::{httpclient, error}; +use utils::httpclient; use utils::constants::*; +use error::prelude::*; #[derive(Debug)] pub struct UpdateProfileDataBuilder { @@ -41,26 +42,26 @@ impl UpdateProfileDataBuilder { } } - pub fn to(&mut self, did: &str) -> Result<&mut Self, u32> { + pub fn to(&mut self, did: &str) -> VcxResult<&mut Self> { validation::validate_did(did)?; self.to_did = did.to_string(); Ok(self) } - pub fn name(&mut self, name: &str) -> Result<&mut Self, u32> { + pub fn name(&mut self, name: &str) -> VcxResult<&mut Self> { let config = ConfigOption { name: "name".to_string(), value: name.to_string() }; self.configs.push(config); Ok(self) } - pub fn logo_url(&mut self, url: &str) -> Result<&mut Self, u32> { + pub fn logo_url(&mut self, url: &str) -> VcxResult<&mut Self> { validation::validate_url(url)?; let config = ConfigOption { name: "logoUrl".to_string(), value: url.to_string() }; self.configs.push(config); Ok(self) } - pub fn use_public_did(&mut self, did: &Option) -> Result<&mut Self, u32> { + pub fn use_public_did(&mut self, did: &Option) -> VcxResult<&mut Self> { if let Some(x) = did { let config = ConfigOption { name: "publicDid".to_string(), value: x.to_string() }; self.configs.push(config); @@ -68,7 +69,7 @@ impl UpdateProfileDataBuilder { Ok(self) } - pub fn send_secure(&mut self) -> Result<(), u32> { + pub fn send_secure(&mut self) -> VcxResult<()> { trace!("UpdateProfileData::send_secure >>>"); if settings::test_agency_mode_enabled() { @@ -77,12 +78,12 @@ impl UpdateProfileDataBuilder { let data = self.prepare_request()?; - let response = httpclient::post_u8(&data).or(Err(error::POST_MSG_FAILURE.code_num))?; + let response = httpclient::post_u8(&data)?; self.parse_response(response) } - fn prepare_request(&self) -> Result, u32> { + fn prepare_request(&self) -> VcxResult> { let message = match settings::get_protocol_type() { settings::ProtocolTypes::V1 => A2AMessage::Version1( @@ -109,13 +110,13 @@ impl UpdateProfileDataBuilder { prepare_message_for_agency(&message, &agency_did) } - fn parse_response(&self, response: Vec) -> Result<(), u32> { + fn parse_response(&self, response: Vec) -> VcxResult<()> { let mut response = parse_response_from_agency(&response)?; match response.remove(0) { A2AMessage::Version1(A2AMessageV1::UpdateConfigsResponse(res)) => Ok(()), A2AMessage::Version2(A2AMessageV2::UpdateConfigsResponse(res)) => Ok(()), - _ => Err(error::INVALID_HTTP_RESPONSE.code_num) + _ => return Err(VcxError::from_msg(VcxErrorKind::InvalidHttpResponse, "Message does not match any variant of UpdateConfigsResponse")) } } } diff --git a/vcx/libvcx/src/messages/validation.rs b/vcx/libvcx/src/messages/validation.rs index a78cd9f211..1dbbae808b 100644 --- a/vcx/libvcx/src/messages/validation.rs +++ b/vcx/libvcx/src/messages/validation.rs @@ -1,51 +1,53 @@ extern crate rust_base58; extern crate openssl; -use self::openssl::bn::{ BigNum }; -use self::rust_base58::{FromBase58}; -use utils::error; +use self::openssl::bn::BigNum; +use self::rust_base58::FromBase58; use url::Url; +use error::prelude::*; -pub fn validate_did(did: &str) -> Result { +pub fn validate_did(did: &str) -> VcxResult { // assert len(base58.b58decode(did)) == 16 let check_did = String::from(did); match check_did.from_base58() { Ok(ref x) if x.len() == 16 => Ok(check_did), - Ok(_) => Err(error::INVALID_DID.code_num), - Err(x) => Err(error::NOT_BASE58.code_num) + Ok(_) => Err(VcxError::from_msg(VcxErrorKind::InvalidDid, "Invalid DID length")), + Err(x) => Err(VcxError::from_msg(VcxErrorKind::NotBase58, format!("Invalid DID: {}", x))), } } -pub fn validate_verkey(verkey: &str) -> Result { +pub fn validate_verkey(verkey: &str) -> VcxResult { // assert len(base58.b58decode(ver_key)) == 32 let check_verkey = String::from(verkey); match check_verkey.from_base58() { Ok(ref x) if x.len() == 32 => Ok(check_verkey), - Ok(_) => Err(error::INVALID_VERKEY.code_num), - Err(x) => Err(error::NOT_BASE58.code_num) + Ok(_) => Err(VcxError::from_msg(VcxErrorKind::InvalidVerkey, "Invalid Verkey length")), + Err(x) => Err(VcxError::from_msg(VcxErrorKind::NotBase58, format!("Invalid Verkey: {}", x))), } } -pub fn validate_nonce(nonce: &str) -> Result { - let nonce = BigNum::from_dec_str(nonce).or(Err(error::INVALID_NONCE.code_num))?; +pub fn validate_nonce(nonce: &str) -> VcxResult { + let nonce = BigNum::from_dec_str(nonce) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidNonce, err))?; if nonce.num_bits() > 80 { - return Err(error::INVALID_NONCE.code_num) + return Err(VcxError::from_msg(VcxErrorKind::InvalidNonce, "Invalid Nonce length")); } Ok(nonce.to_string()) } -pub fn validate_key_delegate(delegate: &str) -> Result { +pub fn validate_key_delegate(delegate: &str) -> VcxResult { //todo: find out what needs to be validated for key_delegate let check_delegate = String::from(delegate); Ok(check_delegate) } -pub fn validate_url(url: &str)->Result{ - Url::parse(url).or(Err(error::INVALID_URL.code_num))?; +pub fn validate_url(url: &str) -> VcxResult { + Url::parse(url) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidUrl, err))?; Ok(url.to_string()) } -pub fn validate_phone_number(p_num: &str)->Result{ +pub fn validate_phone_number(p_num: &str) -> VcxResult { Ok(String::from(p_num)) } @@ -59,7 +61,6 @@ mod tests { match validate_did(&to_did) { Err(x) => panic!("Should be valid did"), Ok(x) => assert_eq!(x, to_did.to_string()) - } } @@ -67,9 +68,8 @@ mod tests { fn test_did_is_b58_but_invalid_length() { let to_did = "8XFh8yBzrpJQmNyZzgoT"; match validate_did(&to_did) { - Err(x) => assert_eq!(x, error::INVALID_DID.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::InvalidDid), Ok(x) => panic!("Should be invalid did"), - } } @@ -77,7 +77,7 @@ mod tests { fn test_validate_did_with_non_base58() { let to_did = "8*Fh8yBzrpJQmNyZzgoTqB"; match validate_did(&to_did) { - Err(x) => assert_eq!(x, error::NOT_BASE58.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::NotBase58), Ok(x) => panic!("Should be invalid did"), } } @@ -88,7 +88,6 @@ mod tests { match validate_verkey(&verkey) { Err(x) => panic!("Should be valid verkey"), Ok(x) => assert_eq!(x, verkey) - } } @@ -96,9 +95,8 @@ mod tests { fn test_verkey_is_b58_but_invalid_length() { let verkey = "8XFh8yBzrpJQmNyZzgoT"; match validate_verkey(&verkey) { - Err(x) => assert_eq!(x, error::INVALID_VERKEY.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::InvalidVerkey), Ok(x) => panic!("Should be invalid verkey"), - } } @@ -106,10 +104,8 @@ mod tests { fn test_validate_verkey_with_non_base58() { let verkey = "*kVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A"; match validate_verkey(&verkey) { - Err(x) => assert_eq!(x, error::NOT_BASE58.code_num), + Err(x) => assert_eq!(x.kind(), VcxErrorKind::NotBase58), Ok(x) => panic!("Should be invalid verkey"), } } - - } \ No newline at end of file diff --git a/vcx/libvcx/src/object_cache/mod.rs b/vcx/libvcx/src/object_cache/mod.rs index c52723c7f8..41f83171f6 100644 --- a/vcx/libvcx/src/object_cache/mod.rs +++ b/vcx/libvcx/src/object_cache/mod.rs @@ -1,12 +1,11 @@ -extern crate rand; - use rand::Rng; use std::sync::Mutex; use std::sync::MutexGuard; use std::collections::HashMap; use std::ops::Deref; use std::ops::DerefMut; -use utils::error; + +use error::prelude::*; pub struct ObjectCache{ pub store: Mutex>>, @@ -23,12 +22,12 @@ impl Default for ObjectCache { impl ObjectCache { - fn _lock_store(&self) -> Result>>, u32> { + fn _lock_store(&self) -> VcxResult>>> { match self.store.lock() { Ok(g) => Ok(g), Err(e) => { error!("Unable to lock Object Store: {:?}", e); - Err(10) + Err(VcxError::from_msg(VcxErrorKind::Common(10), format!("Unable to lock Object Store: {:?}", e))) } } } @@ -41,33 +40,33 @@ impl ObjectCache { store.contains_key(&handle) } - pub fn get(&self, handle:u32, closure: F) -> Result - where F: Fn(&T) -> Result { + pub fn get(&self, handle:u32, closure: F) -> VcxResult + where F: Fn(&T) -> VcxResult { let store = self._lock_store()?; match store.get(&handle) { Some(m) => match m.lock() { Ok(obj) => closure(obj.deref()), - Err(err) => return Err(10) //TODO better error + Err(err) => return Err(VcxError::from_msg(VcxErrorKind::Common(10), "Unable to lock Object Store")) //TODO better error }, - None => return Err(error::INVALID_OBJ_HANDLE.code_num) + None => return Err(VcxError::from_msg(VcxErrorKind::InvalidHandle, format!("Object not found for handle: {}", handle))) } } - pub fn get_mut(&self, handle:u32, closure: F) -> Result - where F: Fn(&mut T) -> Result { + pub fn get_mut(&self, handle:u32, closure: F) -> VcxResult + where F: Fn(&mut T) -> VcxResult { let mut store = self._lock_store()?; match store.get_mut(&handle) { Some(m) => match m.lock() { Ok(mut obj) => closure(obj.deref_mut()), - Err(err) => return Err(10) //TODO better error + Err(err) => return Err(VcxError::from_msg(VcxErrorKind::Common(10), "Unable to lock Object Store")) //TODO better error }, - None => return Err(error::INVALID_OBJ_HANDLE.code_num) + None => return Err(VcxError::from_msg(VcxErrorKind::InvalidHandle, format!("Object not found for handle: {}", handle))) } } - pub fn add(&self, obj:T) -> Result { + pub fn add(&self, obj:T) -> VcxResult { let mut store = self._lock_store()?; let mut new_handle = rand::thread_rng().gen::(); @@ -84,15 +83,15 @@ impl ObjectCache { } } - pub fn release(&self, handle:u32) -> Result<(),u32> { + pub fn release(&self, handle:u32) -> VcxResult<()> { let mut store = self._lock_store()?; match store.remove(&handle) { Some(_) => Ok(()), - None => Err(error::INVALID_OBJ_HANDLE.code_num) + None => return Err(VcxError::from_msg(VcxErrorKind::InvalidHandle, format!("Object not found for handle: {}", handle))) } } - pub fn drain(&self) -> Result<(), u32> { + pub fn drain(&self) -> VcxResult<()> { let mut store = self._lock_store()?; Ok(store.clear()) } diff --git a/vcx/libvcx/src/proof.rs b/vcx/libvcx/src/proof.rs index 18022a2083..a1fa423932 100644 --- a/vcx/libvcx/src/proof.rs +++ b/vcx/libvcx/src/proof.rs @@ -1,27 +1,22 @@ -extern crate rand; -extern crate serde_json; -extern crate libc; -extern crate openssl; +use serde_json; +use serde_json::Value; +use openssl; +use openssl::bn::{BigNum, BigNumRef}; -use self::openssl::bn::{BigNum, BigNumRef}; use settings; use connection; use api::{VcxStateType, ProofStateType}; -use messages::proofs::proof_message::{ProofMessage, CredInfo}; use messages; -use messages::RemoteMessageType; +use messages::proofs::proof_message::{ProofMessage, CredInfo}; +use messages::{RemoteMessageType, ObjectWithVersion, GeneralMessage}; use messages::payload::{Payloads, PayloadKinds, Thread}; use messages::proofs::proof_request::ProofRequestMessage; -use messages::GeneralMessage; use utils::error; use utils::constants::*; -use utils::libindy::anoncreds::libindy_verifier_verify_proof; use utils::libindy::anoncreds; -use error::proof::ProofError; -use error::ToErrorCode; -use serde_json::Value; use utils::constants::DEFAULT_SERIALIZE_VERSION; use object_cache::ObjectCache; +use error::prelude::*; lazy_static! { static ref PROOF_MAP: ObjectCache = Default::default(); @@ -61,7 +56,7 @@ pub struct Proof { impl Proof { // leave this returning a u32 until we actually implement this method to do something // other than return success. - fn validate_proof_request(&self) -> Result { + fn validate_proof_request(&self) -> VcxResult { //TODO: validate proof request Ok(error::SUCCESS.code_num) } @@ -72,19 +67,19 @@ impl Proof { schemas_json: &str, credential_defs_json: &str, rev_reg_defs_json: &str, - rev_regs_json: &str) -> Result { + rev_regs_json: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(error::SUCCESS.code_num); } debug!("starting libindy proof verification for {}", self.source_id); - let valid = libindy_verifier_verify_proof(proof_req_json, - proof_json, - schemas_json, - credential_defs_json, - rev_reg_defs_json, - rev_regs_json).map_err(|err| { + let valid = anoncreds::libindy_verifier_verify_proof(proof_req_json, + proof_json, + schemas_json, + credential_defs_json, + rev_reg_defs_json, + rev_regs_json).map_err(|err| { error!("Error: {}, Proof {} wasn't valid", err, self.source_id); self.proof_state = ProofStateType::ProofInvalid; - ProofError::InvalidProof() + err.map(VcxErrorKind::InvalidProof, error::INVALID_PROOF.message) })?; if !valid { @@ -98,17 +93,16 @@ impl Proof { Ok(error::SUCCESS.code_num) } - fn build_credential_defs_json(&self, credential_data: &Vec) -> Result { + fn build_credential_defs_json(&self, credential_data: &Vec) -> VcxResult { debug!("{} building credential_def_json for proof validation", self.source_id); let mut credential_json = json!({}); for ref cred_info in credential_data.iter() { if credential_json.get(&cred_info.cred_def_id).is_none() { - let (id, credential_def) = anoncreds::get_cred_def_json(&cred_info.cred_def_id) - .map_err(|ec| ProofError::CommonError(ec))?; + let (id, credential_def) = anoncreds::get_cred_def_json(&cred_info.cred_def_id)?; let credential_def = serde_json::from_str(&credential_def) - .or(Err(ProofError::InvalidCredData()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, format!("Cannot deserialize credential definition: {}", err)))?; credential_json[id] = credential_def; } @@ -117,7 +111,7 @@ impl Proof { Ok(credential_json.to_string()) } - fn build_schemas_json(&self, credential_data: &Vec) -> Result { + fn build_schemas_json(&self, credential_data: &Vec) -> VcxResult { debug!("{} building schemas json for proof validation", self.source_id); let mut schemas_json = json!({}); @@ -125,10 +119,10 @@ impl Proof { for ref cred_info in credential_data.iter() { if schemas_json.get(&cred_info.schema_id).is_none() { let (id, schema_json) = anoncreds::get_schema_json(&cred_info.schema_id) - .or(Err(ProofError::InvalidSchema()))?; + .map_err(|err| err.map(VcxErrorKind::InvalidSchema, "Cannot get schema"))?; let schema_val = serde_json::from_str(&schema_json) - .or(Err(ProofError::InvalidSchema()))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidSchema, format!("Cannot deserialize schema: {}", err)))?; schemas_json[id] = schema_val; } @@ -137,7 +131,7 @@ impl Proof { Ok(schemas_json.to_string()) } - fn build_rev_reg_defs_json(&self, credential_data: &Vec) -> Result { + fn build_rev_reg_defs_json(&self, credential_data: &Vec) -> VcxResult { debug!("{} building rev_reg_def_json for proof validation", self.source_id); let mut rev_reg_defs_json = json!({}); @@ -146,14 +140,14 @@ impl Proof { let rev_reg_id = cred_info .rev_reg_id .as_ref() - .ok_or(ProofError::InvalidRevocationInfo())?; + .ok_or(VcxError::from(VcxErrorKind::InvalidRevocationDetails))?; if rev_reg_defs_json.get(rev_reg_id).is_none() { let (id, json) = anoncreds::get_rev_reg_def_json(rev_reg_id) - .or(Err(ProofError::InvalidRevocationInfo()))?; + .or(Err(VcxError::from(VcxErrorKind::InvalidRevocationDetails)))?; let rev_reg_def_json = serde_json::from_str(&json) - .or(Err(ProofError::InvalidSchema()))?; + .or(Err(VcxError::from(VcxErrorKind::InvalidSchema)))?; rev_reg_defs_json[id] = rev_reg_def_json; } @@ -162,7 +156,7 @@ impl Proof { Ok(rev_reg_defs_json.to_string()) } - fn build_rev_reg_json(&self, credential_data: &Vec) -> Result { + fn build_rev_reg_json(&self, credential_data: &Vec) -> VcxResult { debug!("{} building rev_reg_json for proof validation", self.source_id); let mut rev_regs_json = json!({}); @@ -171,19 +165,19 @@ impl Proof { let rev_reg_id = cred_info .rev_reg_id .as_ref() - .ok_or(ProofError::InvalidRevocationInfo())?; + .ok_or(VcxError::from(VcxErrorKind::InvalidRevocationDetails))?; let timestamp = cred_info .timestamp .as_ref() - .ok_or(ProofError::InvalidTimestamp())?; + .ok_or(VcxError::from(VcxErrorKind::InvalidRevocationTimestamp))?; if rev_regs_json.get(rev_reg_id).is_none() { let (id, json, timestamp) = anoncreds::get_rev_reg(rev_reg_id, timestamp.to_owned()) - .or(Err(ProofError::InvalidRevocationInfo()))?; + .or(Err(VcxError::from(VcxErrorKind::InvalidRevocationDetails)))?; let rev_reg_json: Value = serde_json::from_str(&json) - .or(Err(ProofError::InvalidJson()))?; + .or(Err(VcxError::from(VcxErrorKind::InvalidJson)))?; let rev_reg_json = json!({timestamp.to_string(): rev_reg_json}); rev_regs_json[id] = rev_reg_json; @@ -193,27 +187,26 @@ impl Proof { Ok(rev_regs_json.to_string()) } - fn build_proof_json(&self) -> Result { + fn build_proof_json(&self) -> VcxResult { debug!("{} building proof json for proof validation", self.source_id); match self.proof { Some(ref x) => Ok(x.libindy_proof.clone()), - None => Err(ProofError::InvalidProof()), + None => Err(VcxError::from(VcxErrorKind::InvalidProof)), } } - fn build_proof_req_json(&self) -> Result { + fn build_proof_req_json(&self) -> VcxResult { debug!("{} building proof request json for proof validation", self.source_id); if let Some(ref x) = self.proof_request { return Ok(x.get_proof_request_data()); } - - Err(ProofError::InvalidProof()) + Err(VcxError::from(VcxErrorKind::InvalidProof)) } - fn proof_validation(&mut self) -> Result { + fn proof_validation(&mut self) -> VcxResult { let proof_msg = self.proof .clone() - .ok_or(ProofError::InvalidProof())?; + .ok_or(VcxError::from(VcxErrorKind::InvalidProof))?; let credential_data = proof_msg.get_credential_info()?; @@ -242,19 +235,19 @@ impl Proof { &rev_regs_json) } - fn send_proof_request(&mut self, connection_handle: u32) -> Result { + fn send_proof_request(&mut self, connection_handle: u32) -> VcxResult { trace!("Proof::send_proof_request >>> connection_handle: {}", connection_handle); if self.state != VcxStateType::VcxStateInitialized { warn!("proof {} has invalid state {} for sending proofRequest", self.source_id, self.state as u32); - return Err(ProofError::ProofNotReadyError()); + return Err(VcxError::from(VcxErrorKind::NotReady)); } debug!("sending proof request with proof: {}, and connection {}", self.source_id, connection_handle); - self.prover_did = connection::get_pw_did(connection_handle).map_err(|_| ProofError::InvalidConnection())?; - self.agent_did = connection::get_agent_did(connection_handle).map_err(|_| ProofError::InvalidConnection())?; - self.agent_vk = connection::get_agent_verkey(connection_handle).map_err(|_| ProofError::InvalidConnection())?; - self.remote_vk = connection::get_their_pw_verkey(connection_handle).map_err(|_| ProofError::InvalidConnection())?; - self.prover_vk = connection::get_pw_verkey(connection_handle).map_err(|_| ProofError::InvalidConnection())?; + self.prover_did = connection::get_pw_did(connection_handle).or(Err(VcxError::from(VcxErrorKind::GeneralConnectionError)))?; + self.agent_did = connection::get_agent_did(connection_handle).or(Err(VcxError::from(VcxErrorKind::GeneralConnectionError)))?; + self.agent_vk = connection::get_agent_verkey(connection_handle).or(Err(VcxError::from(VcxErrorKind::GeneralConnectionError)))?; + self.remote_vk = connection::get_their_pw_verkey(connection_handle).or(Err(VcxError::from(VcxErrorKind::GeneralConnectionError)))?; + self.prover_vk = connection::get_pw_verkey(connection_handle).or(Err(VcxError::from(VcxErrorKind::GeneralConnectionError)))?; debug!("prover_did: {} -- agent_did: {} -- agent_vk: {} -- remote_vk: {} -- prover_vk: {}", self.prover_did, @@ -266,19 +259,18 @@ impl Proof { let data_version = "0.1"; let mut proof_obj = messages::proof_request(); let proof_request = proof_obj - .type_version(&self.version) - .nonce(&self.nonce) - .proof_name(&self.name) - .proof_data_version(data_version) - .requested_attrs(&self.requested_attrs) - .requested_predicates(&self.requested_predicates) - .from_timestamp(self.revocation_interval.from) - .to_timestamp(self.revocation_interval.to) - .serialize_message() - .map_err(|ec| ProofError::ProofMessageError(ec))?; + .type_version(&self.version)? + .nonce(&self.nonce)? + .proof_name(&self.name)? + .proof_data_version(data_version)? + .requested_attrs(&self.requested_attrs)? + .requested_predicates(&self.requested_predicates)? + .from_timestamp(self.revocation_interval.from)? + .to_timestamp(self.revocation_interval.to)? + .serialize_message()?; self.proof_request = Some(proof_obj); - let title = format!("{} wants you to share: {}", settings::get_config_value(settings::CONFIG_INSTITUTION_NAME).map_err(|e| ProofError::CommonError(e))?, self.name); + let title = format!("{} wants you to share: {}", settings::get_config_value(settings::CONFIG_INSTITUTION_NAME)?, self.name); let response = messages::send_message() .to(&self.prover_did)? @@ -288,23 +280,20 @@ impl Proof { .set_title(&title)? .set_detail(&title)? .agent_vk(&self.agent_vk)? - .edge_agent_payload(&self.prover_vk, &self.remote_vk, &proof_request, PayloadKinds::ProofRequest, self.thread.clone()).or(Err(ProofError::ProofConnectionError()))? + .edge_agent_payload(&self.prover_vk, &self.remote_vk, &proof_request, PayloadKinds::ProofRequest, self.thread.clone()).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle)))? .send_secure() - .map_err(|err| { - warn!("{} could not send proofReq: {}", self.source_id, err); - ProofError::ProofMessageError(err) - })?; + .map_err(|err| err.extend("Cannot send proof request"))?; self.msg_uid = response.get_msg_uid()?; self.state = VcxStateType::VcxStateOfferSent; return Ok(error::SUCCESS.code_num); } - fn get_proof(&self) -> Result { - Ok(self.proof.as_ref().ok_or(ProofError::InvalidHandle())?.libindy_proof.clone()) + fn get_proof(&self) -> VcxResult { + Ok(self.proof.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidProofHandle))?.libindy_proof.clone()) } - fn get_proof_request_status(&mut self) -> Result { + fn get_proof_request_status(&mut self) -> VcxResult { debug!("updating state for proof {} with msg_id {:?}", self.source_id, self.msg_uid); if self.state == VcxStateType::VcxStateAccepted { return Ok(self.get_state()); @@ -314,10 +303,9 @@ impl Proof { let (_, payload) = messages::get_message::get_ref_msg(&self.msg_uid, &self.prover_did, &self.prover_vk, &self.agent_did, - &self.agent_vk) - .map_err(|ec| ProofError::ProofMessageError(ec))?; + &self.agent_vk)?; - let (payload, thread) = Payloads::decrypt(&self.prover_vk, &payload).map_err(|ec| ProofError::CommonError(ec))?; + let (payload, thread) = Payloads::decrypt(&self.prover_vk, &payload)?; self.proof = match parse_proof_payload(&payload) { Err(err) => return Ok(self.get_state()), @@ -340,20 +328,15 @@ impl Proof { } Err(x) => { self.state = VcxStateType::VcxStateRequestReceived; - if x == ProofError::CommonError(error::TIMEOUT_LIBINDY_ERROR.code_num) { - warn!("Proof {} unable to be validated", self.source_id); - self.proof_state = ProofStateType::ProofUndefined; - } else { - warn!("Proof {} had invalid format with err {}", self.source_id, x); - self.proof_state = ProofStateType::ProofInvalid; - } + warn!("Proof {} had invalid format with err {}", self.source_id, x); + self.proof_state = ProofStateType::ProofInvalid; } }; Ok(self.get_state()) } - fn update_state(&mut self) -> Result { + fn update_state(&mut self) -> VcxResult { trace!("Proof::update_state >>>"); self.get_proof_request_status() } @@ -373,19 +356,16 @@ impl Proof { fn get_source_id(&self) -> &String { &self.source_id } - fn to_string(&self) -> String { - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json!(self), - }).to_string() + fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize Proof")) } - fn from_str(s: &str) -> Result { - let s: Value = serde_json::from_str(&s) - .or(Err(ProofError::InvalidJson()))?; - let proof: Proof = serde_json::from_value(s["data"].clone()) - .or(Err(ProofError::InvalidJson()))?; - Ok(proof) + fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize Proof")) } } @@ -393,14 +373,14 @@ pub fn create_proof(source_id: String, requested_attrs: String, requested_predicates: String, revocation_details: String, - name: String) -> Result { + name: String) -> VcxResult { trace!("create_proof >>> source_id: {}, requested_attrs: {}, requested_predicates: {}, name: {}", source_id, requested_attrs, requested_predicates, name); // TODO: Get this to actually validate as json, not just check length. - if requested_attrs.len() <= 0 { return Err(ProofError::CommonError(error::INVALID_JSON.code_num)); } + if requested_attrs.len() <= 0 { return Err(VcxError::from(VcxErrorKind::InvalidJson)); } let revocation_details: RevocationInterval = serde_json::from_str(&revocation_details) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + .or(Err(VcxError::from(VcxErrorKind::InvalidJson)))?; debug!("creating proof with source_id: {}, name: {}, requested_attrs: {}, requested_predicates: {}", source_id, name, requested_attrs, requested_predicates); @@ -416,7 +396,7 @@ pub fn create_proof(source_id: String, proof_state: ProofStateType::ProofUndefined, name, version: String::from("1.0"), - nonce: generate_nonce().map_err(|ec| ProofError::CommonError(ec))?, + nonce: generate_nonce()?, proof: None, proof_request: None, remote_did: String::new(), @@ -427,20 +407,19 @@ pub fn create_proof(source_id: String, thread: Some(Thread::new()), }; - new_proof.validate_proof_request().map_err(|ec| ProofError::CommonError(ec))?; + new_proof.validate_proof_request()?; new_proof.state = VcxStateType::VcxStateInitialized; - let new_handle = PROOF_MAP.add(new_proof).map_err(|ec| ProofError::CreateProofError())?; - - Ok(new_handle) + PROOF_MAP.add(new_proof) + .or(Err(VcxError::from(VcxErrorKind::CreateProof))) } pub fn is_valid_handle(handle: u32) -> bool { PROOF_MAP.has_handle(handle) } -pub fn update_state(handle: u32) -> Result { +pub fn update_state(handle: u32) -> VcxResult { PROOF_MAP.get_mut(handle, |p| { match p.update_state() { Ok(x) => Ok(x), @@ -449,92 +428,81 @@ pub fn update_state(handle: u32) -> Result { Ok(p.get_state()) } } - }).map_err(|ec| ProofError::CommonError(ec)) + }) } -pub fn get_state(handle: u32) -> Result { +pub fn get_state(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { Ok(p.get_state()) - }).map_err(|ec| ProofError::CommonError(ec)) + }) } -pub fn get_proof_state(handle: u32) -> Result { +pub fn get_proof_state(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { Ok(p.get_proof_state()) - }).map_err(|ec| ProofError::CommonError(ec)) + }) } -pub fn release(handle: u32) -> Result<(), ProofError> { - match PROOF_MAP.release(handle) { - Ok(_) => Ok(()), - Err(_) => Err(ProofError::InvalidHandle()), - } +pub fn release(handle: u32) -> VcxResult<()> { + PROOF_MAP.release(handle).or(Err(VcxError::from(VcxErrorKind::InvalidProofHandle))) } pub fn release_all() { - match PROOF_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + PROOF_MAP.drain().ok(); } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { - Ok(Proof::to_string(&p)) - }).map_err(|ec| ProofError::CommonError(ec)) + Proof::to_string(&p) + }) } -pub fn get_source_id(handle: u32) -> Result { +pub fn get_source_id(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { Ok(p.get_source_id().clone()) - }).map_err(|ec| ProofError::CommonError(ec)) + }) } -pub fn from_string(proof_data: &str) -> Result { - let derived_proof: Proof = Proof::from_str(proof_data).map_err(|err| { - warn!("{} with serde error: {}", error::INVALID_JSON.message, err); - ProofError::CommonError(error::INVALID_JSON.code_num) - })?; +pub fn from_string(proof_data: &str) -> VcxResult { + let derived_proof: Proof = Proof::from_str(proof_data) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize Proof: {}", err)))?; let source_id = derived_proof.source_id.clone(); - let new_handle = PROOF_MAP.add(derived_proof).map_err(|ec| ProofError::CommonError(ec))?; - - Ok(new_handle) + PROOF_MAP.add(derived_proof) } -pub fn send_proof_request(handle: u32, connection_handle: u32) -> Result { +pub fn send_proof_request(handle: u32, connection_handle: u32) -> VcxResult { PROOF_MAP.get_mut(handle, |p| { - p.send_proof_request(connection_handle).map_err(|ec| ec.to_error_code()) - }).map_err(|ec| ProofError::CommonError(ec)) + p.send_proof_request(connection_handle) + }) } -pub fn get_proof_uuid(handle: u32) -> Result { +pub fn get_proof_uuid(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { Ok(p.get_proof_uuid().clone()) }) } -fn parse_proof_payload(payload: &str) -> Result { - let my_credential_req = ProofMessage::from_str(&payload).map_err(|err| { - warn!("invalid json {}", err); - error::INVALID_JSON.code_num - })?; +fn parse_proof_payload(payload: &str) -> VcxResult { + let my_credential_req = ProofMessage::from_str(&payload) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize ProofMessage: {}", err)))?; Ok(my_credential_req) } -pub fn get_proof(handle: u32) -> Result { +pub fn get_proof(handle: u32) -> VcxResult { PROOF_MAP.get(handle, |p| { - p.get_proof().map_err(|ec| ec.to_error_code()) - }).map_err(|ec| ProofError::CommonError(ec)) + p.get_proof() + }) } // TODO: This doesnt feel like it should be here (maybe utils?) -pub fn generate_nonce() -> Result { - let mut bn = BigNum::new().map_err(|err| error::BIG_NUMBER_ERROR.code_num)?; +pub fn generate_nonce() -> VcxResult { + let mut bn = BigNum::new().map_err(|err| VcxError::from_msg(VcxErrorKind::EncodeError, format!("Cannot generate nonce: {}", err)))?; BigNumRef::rand(&mut bn, LARGE_NONCE as i32, openssl::bn::MsbOption::MAYBE_ZERO, false) - .map_err(|_| error::BIG_NUMBER_ERROR.code_num)?; - Ok(bn.to_dec_str().map_err(|err| error::BIG_NUMBER_ERROR.code_num)?.to_string()) + .map_err(|err| VcxError::from_msg(VcxErrorKind::EncodeError, format!("Cannot generate nonce: {}", err)))?; + Ok(bn.to_dec_str() + .map_err(|err| VcxError::from_msg(VcxErrorKind::EncodeError, format!("Cannot generate nonce: {}", err)))?.to_string()) } #[cfg(test)] @@ -909,11 +877,11 @@ mod tests { let h4 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); let h5 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); release_all(); - assert_eq!(release(h1).err(), Some(ProofError::InvalidHandle())); - assert_eq!(release(h2).err(), Some(ProofError::InvalidHandle())); - assert_eq!(release(h3).err(), Some(ProofError::InvalidHandle())); - assert_eq!(release(h4).err(), Some(ProofError::InvalidHandle())); - assert_eq!(release(h5).err(), Some(ProofError::InvalidHandle())); + assert_eq!(release(h1).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); + assert_eq!(release(h2).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); + assert_eq!(release(h3).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); + assert_eq!(release(h4).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); + assert_eq!(release(h5).unwrap_err().kind(), VcxErrorKind::InvalidProofHandle); } #[ignore] @@ -973,7 +941,7 @@ mod tests { r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); set_libindy_rc(error::TIMEOUT_LIBINDY_ERROR.code_num); - assert_eq!(send_proof_request(handle, connection_handle).err(), Some(ProofError::CommonError(error::TIMEOUT_LIBINDY_ERROR.code_num))); + assert_eq!(send_proof_request(handle, connection_handle).unwrap_err().kind(), VcxErrorKind::TimeoutLibindy); assert_eq!(get_state(handle).unwrap(), VcxStateType::VcxStateInitialized as u32); assert_eq!(get_proof_uuid(handle).unwrap(), ""); @@ -1015,21 +983,17 @@ mod tests { #[test] fn test_proof_errors() { - use utils::error::{INVALID_JSON, POST_MSG_FAILURE}; init!("false"); let mut proof = create_boxed_proof(); - assert_eq!(proof.validate_proof_indy("{}", "{}", "{}", "{}", "", "").err(), - Some(ProofError::InvalidProof())); + assert_eq!(proof.validate_proof_indy("{}", "{}", "{}", "{}", "", "").unwrap_err().kind(), VcxErrorKind::InvalidProof);; let bad_handle = 100000; // TODO: Do something to guarantee that this handle is bad - assert_eq!(proof.send_proof_request(bad_handle).err(), - Some(ProofError::ProofNotReadyError())); + assert_eq!(proof.send_proof_request(bad_handle).unwrap_err().kind(), VcxErrorKind::NotReady); // TODO: Add test that returns a INVALID_PROOF_CREDENTIAL_DATA - assert_eq!(proof.get_proof_request_status().err(), - Some(ProofError::ProofMessageError(POST_MSG_FAILURE.code_num))); + assert_eq!(proof.get_proof_request_status().unwrap_err().kind(), VcxErrorKind::PostMessageFailed);; let empty = r#""#; @@ -1037,14 +1001,13 @@ mod tests { empty.to_string(), "{}".to_string(), r#"{"support_revocation":false}"#.to_string(), - "my name".to_string()).err(), - Some(ProofError::CommonError(INVALID_JSON.code_num))); + "my name".to_string()).unwrap_err().kind(), VcxErrorKind::InvalidJson);; - assert_eq!(to_string(bad_handle).err(), Some(ProofError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); - assert_eq!(get_source_id(bad_handle).err(), Some(ProofError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); - assert_eq!(from_string(empty).err(), Some(ProofError::CommonError(INVALID_JSON.code_num))); + assert_eq!(to_string(bad_handle).unwrap_err().kind(), VcxErrorKind::InvalidHandle);; + assert_eq!(get_source_id(bad_handle).unwrap_err().kind(), VcxErrorKind::InvalidHandle);; + assert_eq!(from_string(empty).unwrap_err().kind(), VcxErrorKind::InvalidJson);; let mut proof_good = create_boxed_proof(); - assert_eq!(proof_good.get_proof_request_status().err(), Some(ProofError::ProofMessageError(POST_MSG_FAILURE.code_num))); + assert_eq!(proof_good.get_proof_request_status().unwrap_err().kind(), VcxErrorKind::PostMessageFailed); } #[cfg(feature = "agency")] diff --git a/vcx/libvcx/src/schema.rs b/vcx/libvcx/src/schema.rs index 87f6869144..6da705a36c 100644 --- a/vcx/libvcx/src/schema.rs +++ b/vcx/libvcx/src/schema.rs @@ -1,16 +1,14 @@ use serde_json; -use serde_json::Value; -extern crate rand; -use settings; -use std::fmt; use std::string::ToString; -use utils::error; + +use settings; use utils::libindy::anoncreds; use utils::libindy::payments::PaymentTxn; -use error::schema::SchemaError; use utils::constants::DEFAULT_SERIALIZE_VERSION; use object_cache::ObjectCache; +use messages::ObjectWithVersion; +use error::prelude::*; lazy_static! { static ref SCHEMA_MAP: ObjectCache = Default::default(); @@ -24,73 +22,37 @@ pub struct SchemaData { attr_names: Vec, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct CreateSchema { data: Vec, version: String, schema_id: String, name: String, source_id: String, - sequence_num: u32, payment_txn: Option, } -impl Default for CreateSchema { - fn default() -> CreateSchema { - CreateSchema { - data: Vec::new(), - version: String::new(), - schema_id: String::new(), - name: String::new(), - source_id: String::new(), - sequence_num: 0, - payment_txn: None, - } - } -} - -impl fmt::Display for CreateSchema { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match serde_json::to_string(&self){ - Ok(s) => { - write!(f, "{}", s) - }, - Err(e) => { - error!("{}: {:?}",error::INVALID_SCHEMA.message, e); - write!(f, "null") - } - } - } -} - impl CreateSchema { - - pub fn set_sequence_num(&mut self, sequence_num: u32) {self.sequence_num = sequence_num;} - - pub fn get_sequence_num(&self) -> u32 {let sequence_num = self.sequence_num as u32; sequence_num} - pub fn get_source_id(&self) -> &String { &self.source_id } pub fn get_schema_id(&self) -> &String { &self.schema_id } - fn get_payment_txn(&self) -> Result { + fn get_payment_txn(&self) -> VcxResult { trace!("CreateSchema::get_payment_txn >>>"); - Ok(self.payment_txn.clone().ok_or(error::NOT_READY.code_num)?) + self.payment_txn.clone() + .ok_or(VcxError::from(VcxErrorKind::NoPaymentInformation)) } - fn to_string_with_version(&self) -> String { - json!({ - "version": DEFAULT_SERIALIZE_VERSION, - "data": json!(self), - }).to_string() + fn to_string(&self) -> VcxResult { + ObjectWithVersion::new(DEFAULT_SERIALIZE_VERSION, self.to_owned()) + .serialize() + .map_err(|err| err.extend("Cannot serialize Schema")) } - fn from_str(data: &str) -> Result { - let data:Value = serde_json::from_str(&data) - .or(Err(SchemaError::InvalidSchemaCreation()))?; - let schema: CreateSchema = serde_json::from_value(data["data"].clone()) - .or(Err(SchemaError::InvalidSchemaCreation()))?; - Ok(schema) + fn from_str(data: &str) -> VcxResult { + ObjectWithVersion::deserialize(data) + .map(|obj: ObjectWithVersion| obj.data) + .map_err(|err| err.extend("Cannot deserialize Schema")) } } @@ -98,124 +60,96 @@ pub fn create_new_schema(source_id: &str, issuer_did: String, name: String, version: String, - data: String) -> Result { - trace!("create_new_schema >>> source_id: {}, issuer_did: {}, name: {}, version: {}, data: {}", - source_id, issuer_did, name, version, data); - + data: String) -> VcxResult { + trace!("create_new_schema >>> source_id: {}, issuer_did: {}, name: {}, version: {}, data: {}", source_id, issuer_did, name, version, data); debug!("creating schema with source_id: {}, name: {}, issuer_did: {}", source_id, name, issuer_did); - let (schema_id, payment_txn) = anoncreds::create_schema(&name, &version, &data) - .map_err(|e| { - if e == error::UNKNOWN_SCHEMA_REJECTION.code_num {SchemaError::UnknownRejection()} - else if e == error::DUPLICATE_SCHEMA.code_num {SchemaError::DuplicateSchema()} - else {SchemaError::CommonError(e)} - })?; + let (schema_id, payment_txn) = anoncreds::create_schema(&name, &version, &data)?; debug!("created schema on ledger with id: {}", schema_id); - let new_schema = CreateSchema { + let schema = CreateSchema { source_id: source_id.to_string(), name, data: serde_json::from_str(&data).unwrap_or_default(), version, schema_id, - //Todo: Take sequence number out. Id will be used instead - sequence_num: 0, payment_txn, }; - let new_handle = SCHEMA_MAP.add(new_schema).map_err(|key|SchemaError::InvalidSchemaCreation())?; - - Ok(new_handle) + SCHEMA_MAP.add(schema) + .or(Err(VcxError::from(VcxErrorKind::CreateSchema))) } -pub fn get_schema_attrs(source_id: String, schema_id: String) -> Result<(u32, String), SchemaError> { +pub fn get_schema_attrs(source_id: String, schema_id: String) -> VcxResult<(u32, String)> { trace!("get_schema_attrs >>> source_id: {}, schema_id: {}", source_id, schema_id); - let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID) - .map_err(|e| SchemaError::CommonError(e))?; + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; - let (schema_id, schema_json) = anoncreds::get_schema_json(&schema_id) - .or(Err(SchemaError::InvalidSchemaSeqNo()))?; + let (schema_id, schema_data_json) = anoncreds::get_schema_json(&schema_id) + .map_err(|err| err.map(VcxErrorKind::InvalidSchemaSeqNo, "Schema not found"))?; - let schema_data: SchemaData = serde_json::from_str(&schema_json) - .or(Err(SchemaError::CommonError(error::INVALID_JSON.code_num)))?; + let schema_data: SchemaData = serde_json::from_str(&schema_data_json) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize schema: {}", err)))?; - let new_schema = CreateSchema { + let schema = CreateSchema { source_id, schema_id, - sequence_num: 0, name: schema_data.name, version: schema_data.version, data: schema_data.attr_names, payment_txn: None, }; - let new_handle = SCHEMA_MAP.add(new_schema).map_err(|key|SchemaError::InvalidSchemaCreation())?; + let schema_json = schema.to_string()?; - Ok((new_handle, to_string(new_handle)?)) + let handle = SCHEMA_MAP.add(schema) + .or(Err(VcxError::from(VcxErrorKind::CreateSchema)))?; + + Ok((handle, schema_json)) } pub fn is_valid_handle(handle: u32) -> bool { SCHEMA_MAP.has_handle(handle) } -pub fn get_sequence_num(handle: u32) -> Result { - SCHEMA_MAP.get(handle,|s|{ - Ok(s.get_sequence_num()) - }).map_err(|ec|SchemaError::CommonError(ec)) -} - -pub fn to_string(handle: u32) -> Result { - SCHEMA_MAP.get(handle,|s|{ - Ok(s.to_string_with_version().to_owned()) - }).map_err(|ec|SchemaError::CommonError(ec)) +pub fn to_string(handle: u32) -> VcxResult { + SCHEMA_MAP.get(handle, |s| { + s.to_string() + }) } -pub fn get_source_id(handle: u32) -> Result { - SCHEMA_MAP.get(handle,|s|{ - Ok(s.get_source_id().clone()) +pub fn get_source_id(handle: u32) -> VcxResult { + SCHEMA_MAP.get(handle, |s| { + Ok(s.get_source_id().to_string()) }) } -pub fn get_schema_id(handle: u32) -> Result { - SCHEMA_MAP.get(handle,|s|{ - Ok(s.get_schema_id().clone()) - }).map_err(|ec|SchemaError::CommonError(ec)) +pub fn get_schema_id(handle: u32) -> VcxResult { + SCHEMA_MAP.get(handle, |s| { + Ok(s.get_schema_id().to_string()) + }) } -pub fn get_payment_txn(handle: u32) -> Result { - SCHEMA_MAP.get(handle,|s|{ +pub fn get_payment_txn(handle: u32) -> VcxResult { + SCHEMA_MAP.get(handle, |s| { s.get_payment_txn() - }).or(Err(SchemaError::NoPaymentInformation())) + }) } -pub fn from_string(schema_data: &str) -> Result { - let derived_schema: CreateSchema = CreateSchema::from_str(schema_data) - .map_err(|_| { - error!("Invalid Json format for CreateSchema string"); - SchemaError::CommonError(error::INVALID_JSON.code_num) - })?; - - let source_id = derived_schema.source_id.clone(); - let new_handle = SCHEMA_MAP.add(derived_schema).map_err(|ec|SchemaError::CommonError(ec))?; - - Ok(new_handle) +pub fn from_string(schema_data: &str) -> VcxResult { + let schema: CreateSchema = CreateSchema::from_str(schema_data)?; + SCHEMA_MAP.add(schema) } -pub fn release(handle: u32) -> Result<(), SchemaError> { - match SCHEMA_MAP.release(handle) { - Ok(_) => Ok(()), - Err(_) => Err(SchemaError::InvalidHandle()), - } +pub fn release(handle: u32) -> VcxResult<()> { + SCHEMA_MAP.release(handle) + .or(Err(VcxError::from(VcxErrorKind::InvalidSchemaHandle))) } pub fn release_all() { - match SCHEMA_MAP.drain() { - Ok(_) => (), - Err(_) => (), - }; + SCHEMA_MAP.drain().ok(); } #[cfg(test)] @@ -225,20 +159,20 @@ pub mod tests { use super::*; #[allow(unused_imports)] use rand::Rng; - use utils::constants::{ SCHEMA_ID, SCHEMA_JSON }; + use utils::constants::{SCHEMA_ID, SCHEMA_JSON}; pub fn create_schema_real() -> u32 { let data = r#"["address1","address2","zip","city","state"]"#.to_string(); let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); - let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), - rand::thread_rng().gen::().to_string()); + let schema_version: String = format!("{}.{}", rand::thread_rng().gen::().to_string(), + rand::thread_rng().gen::().to_string()); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); create_new_schema("id", did, schema_name, schema_version, data).unwrap() } #[test] - fn test_create_schema_to_string(){ + fn test_create_schema_to_string() { let source_id = "testId"; let create_schema = CreateSchema { data: vec!["name".to_string(), "age".to_string(), "sex".to_string(), "height".to_string()], @@ -246,14 +180,11 @@ pub mod tests { schema_id: SCHEMA_ID.to_string(), source_id: "testId".to_string(), name: "schema_name".to_string(), - sequence_num: 306, payment_txn: None, }; - let create_schema_str = r#"{"data":["name","age","sex","height"],"version":"1.0","schema_id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4","name":"schema_name","source_id":"testId","sequence_num":306,"payment_txn":null}"#; - assert_eq!(create_schema.to_string(), create_schema_str.to_string()); - let value: serde_json::Value = serde_json::from_str(&create_schema.to_string_with_version()).unwrap(); + let value: serde_json::Value = serde_json::from_str(&create_schema.to_string().unwrap()).unwrap(); assert_eq!(value["version"], "1.0"); - let create_schema:CreateSchema = serde_json::from_str(&value["data"].to_string()).unwrap(); + let create_schema: CreateSchema = serde_json::from_str(&value["data"].to_string()).unwrap(); assert_eq!(create_schema.source_id, source_id); use utils::constants::SCHEMA_WITH_VERSION; let handle = from_string(SCHEMA_WITH_VERSION).unwrap(); @@ -261,11 +192,11 @@ pub mod tests { let value: serde_json::Value = serde_json::from_str(&schema_str).unwrap(); assert_eq!(value["version"], "1.0"); let data = value["data"].clone(); - let schema:CreateSchema = serde_json::from_str(&data.to_string()).unwrap(); + let schema: CreateSchema = serde_json::from_str(&data.to_string()).unwrap(); } #[test] - fn test_create_schema_success(){ + fn test_create_schema_success() { init!("true"); let data = r#"["name","male"]"#; assert!(create_new_schema("1", @@ -276,37 +207,37 @@ pub mod tests { } #[test] - fn test_get_schema_attrs_success(){ + fn test_get_schema_attrs_success() { init!("true"); - let (handle, schema_attrs ) = get_schema_attrs("Check For Success".to_string(), SCHEMA_ID.to_string()).unwrap(); + let (handle, schema_attrs) = get_schema_attrs("Check For Success".to_string(), SCHEMA_ID.to_string()).unwrap(); assert!(schema_attrs.contains(r#""schema_id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4""#)); assert!(schema_attrs.contains(r#""data":["height","name","sex","age"]"#)); assert!(handle > 0); } #[test] - fn test_create_schema_fails(){ + fn test_create_schema_fails() { init!("false"); let schema = create_new_schema("1", "VsKV7grR1BUE29mG2Fm2kX".to_string(), "name".to_string(), "1.0".to_string(), "".to_string()); - assert_eq!(schema, Err(SchemaError::CommonError(error::INVALID_LIBINDY_PARAM.code_num))) + assert_eq!(schema.unwrap_err().kind(), VcxErrorKind::InvalidLibindyParam) } #[cfg(feature = "pool_tests")] #[test] - fn test_get_schema_attrs_from_ledger(){ + fn test_get_schema_attrs_from_ledger() { init!("ledger"); let (schema_id, _) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); - let (_, schema_attrs ) = get_schema_attrs("id".to_string(), schema_id.clone()).unwrap(); + let (_, schema_attrs) = get_schema_attrs("id".to_string(), schema_id.clone()).unwrap(); assert!(schema_attrs.contains(&schema_id)); } #[cfg(feature = "pool_tests")] #[test] - fn test_create_schema_with_pool(){ + fn test_create_schema_with_pool() { init!("ledger"); let handle = create_schema_real(); let payment = serde_json::to_string(&get_payment_txn(handle).unwrap()).unwrap(); @@ -318,9 +249,9 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] - fn test_create_schema_no_fees_with_pool(){ + fn test_create_schema_no_fees_with_pool() { init!("ledger"); - ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0),Some(0),Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); + ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0), Some(0), Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); let handle = create_schema_real(); assert!(handle > 0); @@ -329,22 +260,22 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] - fn test_create_duplicate_fails_no_fees(){ + fn test_create_duplicate_fails_no_fees() { use settings; init!("ledger"); - ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0),Some(0),Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); + ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0), Some(0), Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let data = r#"["address1","address2","zip","city","state"]"#.to_string(); let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); - let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), + let schema_version: String = format!("{}.{}", rand::thread_rng().gen::().to_string(), rand::thread_rng().gen::().to_string()); let rc = create_new_schema("id", did.clone(), schema_name.clone(), schema_version.clone(), data.clone()); assert!(rc.is_ok()); let rc = create_new_schema("id", did.clone(), schema_name.clone(), schema_version.clone(), data.clone()); - assert_eq!(rc, Err(SchemaError::DuplicateSchema())); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::DuplicationSchema) } #[test] @@ -353,24 +284,23 @@ pub mod tests { let data = r#"["address1","address2","zip","city","state"]"#; let version = r#"0.0.0"#; let did = r#"2hoqvcwupRTUNkXn6ArYzs"#; - let h1 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(),data.to_string()).unwrap(); - let h2 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(),data.to_string()).unwrap(); - let h3 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(),data.to_string()).unwrap(); - let h4 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(),data.to_string()).unwrap(); - let h5 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(),data.to_string()).unwrap(); + let h1 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(), data.to_string()).unwrap(); + let h2 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(), data.to_string()).unwrap(); + let h3 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(), data.to_string()).unwrap(); + let h4 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(), data.to_string()).unwrap(); + let h5 = create_new_schema("1", did.to_string(), "name".to_string(), version.to_string(), data.to_string()).unwrap(); release_all(); - assert_eq!(release(h1).err(),Some(SchemaError::InvalidHandle())); - assert_eq!(release(h2).err(),Some(SchemaError::InvalidHandle())); - assert_eq!(release(h3).err(),Some(SchemaError::InvalidHandle())); - assert_eq!(release(h4).err(),Some(SchemaError::InvalidHandle())); - assert_eq!(release(h5).err(),Some(SchemaError::InvalidHandle())); + assert_eq!(release(h1).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); + assert_eq!(release(h2).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); + assert_eq!(release(h3).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); + assert_eq!(release(h4).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); + assert_eq!(release(h5).unwrap_err().kind(), VcxErrorKind::InvalidSchemaHandle); } #[test] - fn test_errors(){ + fn test_errors() { init!("false"); - assert_eq!(get_sequence_num(145661).err(), Some(SchemaError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); - assert_eq!(to_string(13435178).err(), Some(SchemaError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); + assert_eq!(to_string(13435178).unwrap_err().kind(), VcxErrorKind::InvalidHandle); } #[test] diff --git a/vcx/libvcx/src/settings.rs b/vcx/libvcx/src/settings.rs index 6b257609ed..21a5974d66 100644 --- a/vcx/libvcx/src/settings.rs +++ b/vcx/libvcx/src/settings.rs @@ -11,6 +11,8 @@ use std::fs; use std::io::prelude::*; use serde_json::Value; +use error::prelude::*; + pub static CONFIG_POOL_NAME: &'static str = "pool_name"; pub static CONFIG_PROTOCOL_TYPE: &'static str = "protocol_type"; pub static CONFIG_AGENCY_ENDPOINT: &'static str = "agency_endpoint"; @@ -80,6 +82,7 @@ impl ToString for HashMap { v } } + pub fn set_defaults() -> u32 { trace!("set_defaults >>>"); @@ -112,44 +115,44 @@ pub fn set_defaults() -> u32 { error::SUCCESS.code_num } -pub fn validate_config(config: &HashMap) -> Result { +pub fn validate_config(config: &HashMap) -> VcxResult { trace!("validate_config >>> config: {:?}", config); //Mandatory parameters if config.get(CONFIG_WALLET_KEY).is_none() { - return Err(error::MISSING_WALLET_KEY.code_num); + return Err(VcxError::from(VcxErrorKind::MissingWalletKey)); } // If values are provided, validate they're in the correct format - validate_optional_config_val(config.get(CONFIG_INSTITUTION_DID), error::INVALID_DID.code_num, validation::validate_did)?; - validate_optional_config_val(config.get(CONFIG_INSTITUTION_VERKEY), error::INVALID_VERKEY.code_num, validation::validate_verkey)?; + validate_optional_config_val(config.get(CONFIG_INSTITUTION_DID), VcxErrorKind::InvalidDid, validation::validate_did)?; + validate_optional_config_val(config.get(CONFIG_INSTITUTION_VERKEY), VcxErrorKind::InvalidVerkey, validation::validate_verkey)?; - validate_optional_config_val(config.get(CONFIG_AGENCY_DID), error::INVALID_DID.code_num, validation::validate_did)?; - validate_optional_config_val(config.get(CONFIG_AGENCY_VERKEY), error::INVALID_VERKEY.code_num, validation::validate_verkey)?; + validate_optional_config_val(config.get(CONFIG_AGENCY_DID), VcxErrorKind::InvalidDid, validation::validate_did)?; + validate_optional_config_val(config.get(CONFIG_AGENCY_VERKEY), VcxErrorKind::InvalidVerkey, validation::validate_verkey)?; - validate_optional_config_val(config.get(CONFIG_SDK_TO_REMOTE_DID), error::INVALID_DID.code_num, validation::validate_did)?; - validate_optional_config_val(config.get(CONFIG_SDK_TO_REMOTE_VERKEY), error::INVALID_VERKEY.code_num, validation::validate_verkey)?; + validate_optional_config_val(config.get(CONFIG_SDK_TO_REMOTE_DID), VcxErrorKind::InvalidDid, validation::validate_did)?; + validate_optional_config_val(config.get(CONFIG_SDK_TO_REMOTE_VERKEY), VcxErrorKind::InvalidVerkey, validation::validate_verkey)?; - validate_optional_config_val(config.get(CONFIG_REMOTE_TO_SDK_DID), error::INVALID_DID.code_num, validation::validate_did)?; - validate_optional_config_val(config.get(CONFIG_REMOTE_TO_SDK_VERKEY), error::INVALID_VERKEY.code_num, validation::validate_verkey)?; + validate_optional_config_val(config.get(CONFIG_REMOTE_TO_SDK_DID), VcxErrorKind::InvalidDid, validation::validate_did)?; + validate_optional_config_val(config.get(CONFIG_REMOTE_TO_SDK_VERKEY), VcxErrorKind::InvalidVerkey, validation::validate_verkey)?; - validate_optional_config_val(config.get(CONFIG_AGENCY_ENDPOINT), error::INVALID_URL.code_num, Url::parse)?; - validate_optional_config_val(config.get(CONFIG_INSTITUTION_LOGO_URL), error::INVALID_URL.code_num, Url::parse)?; + validate_optional_config_val(config.get(CONFIG_AGENCY_ENDPOINT), VcxErrorKind::InvalidUrl, Url::parse)?; + validate_optional_config_val(config.get(CONFIG_INSTITUTION_LOGO_URL), VcxErrorKind::InvalidUrl, Url::parse)?; Ok(error::SUCCESS.code_num) } -fn validate_wallet_key(key: &str) -> Result { - if key == UNINITIALIZED_WALLET_KEY { return Err(error::MISSING_WALLET_KEY.code_num); } +fn validate_wallet_key(key: &str) -> VcxResult { + if key == UNINITIALIZED_WALLET_KEY { return Err(VcxError::from(VcxErrorKind::MissingWalletKey)); } Ok(error::SUCCESS.code_num) } -fn validate_optional_config_val(val: Option<&String>, err: u32, closure: F) -> Result +fn validate_optional_config_val(val: Option<&String>, err: VcxErrorKind, closure: F) -> VcxResult where F: Fn(&str) -> Result { if val.is_none() { return Ok(error::SUCCESS.code_num); } - closure(val.as_ref().ok_or(error::INVALID_CONFIGURATION.code_num)?) - .or(Err(err))?; + closure(val.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidConfiguration))?) + .or(Err(VcxError::from(err)))?; Ok(error::SUCCESS.code_num) } @@ -190,27 +193,29 @@ pub fn test_agency_mode_enabled() -> bool { } } -pub fn process_config_string(config: &str) -> Result { +pub fn process_config_string(config: &str) -> VcxResult { trace!("process_config_string >>> config {}", config); - let configuration: Value = serde_json::from_str(config).or(Err(error::INVALID_JSON.code_num))?; + let configuration: Value = serde_json::from_str(config) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize config: {}", err)))?; + if let Value::Object(ref map) = configuration { for (key, value) in map { - set_config_value(key, value.as_str().ok_or(error::INVALID_JSON.code_num)?); + set_config_value(key, value.as_str().ok_or(VcxError::from(VcxErrorKind::InvalidJson))?); } } validate_config( - &SETTINGS.read().or(Err(error::INVALID_CONFIGURATION.code_num))?.clone() + &SETTINGS.read().or(Err(VcxError::from(VcxErrorKind::InvalidConfiguration)))?.clone() ) } -pub fn process_config_file(path: &str) -> Result { +pub fn process_config_file(path: &str) -> VcxResult { trace!("process_config_file >>> path: {}", path); if !Path::new(path).is_file() { error!("Configuration path was invalid"); - Err(error::INVALID_CONFIGURATION.code_num) + Err(VcxError::from_msg(VcxErrorKind::InvalidConfiguration, "Cannot find config file")) } else { process_config_string(&read_config_file(path)?) } @@ -225,7 +230,7 @@ pub fn get_protocol_version() -> usize { Err(err) => { info!("Can't fetch protocol version from config ({}), use default one ({})", err, DEFAULT_PROTOCOL_VERSION); DEFAULT_PROTOCOL_VERSION - }, + } }; if protocol_version > MAX_SUPPORTED_PROTOCOL_VERSION { error!("Protocol version from config {}, greater then maximal supported {}, use maximum one", @@ -236,19 +241,22 @@ pub fn get_protocol_version() -> usize { } } -pub fn get_config_value(key: &str) -> Result { +pub fn get_config_value(key: &str) -> VcxResult { trace!("get_config_value >>> key: {}", key); SETTINGS .read() - .or(Err(error::INVALID_CONFIGURATION.code_num))? + .or(Err(VcxError::from_msg(VcxErrorKind::InvalidConfiguration, "Cannot read settings")))? .get(key) - .map_or(Err(error::INVALID_CONFIGURATION.code_num), |v| Ok(v.to_string())) + .map(|v| v.to_string()) + .ok_or(VcxError::from_msg(VcxErrorKind::InvalidConfiguration, format!("Cannot read \"{}\" from settings", key))) } pub fn set_config_value(key: &str, value: &str) { trace!("set_config_value >>> key: {}, value: {}", key, value); - SETTINGS.write().unwrap().insert(key.to_string(), value.to_string()); + SETTINGS + .write().unwrap() + .insert(key.to_string(), value.to_string()); } pub fn get_wallet_config(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>) -> String { @@ -256,7 +264,7 @@ pub fn get_wallet_config(wallet_name: &str, wallet_type: Option<&str>, storage_c "id": wallet_name, "storage_type": wallet_type }); - + let storage_config = get_config_value(CONFIG_WALLET_STORAGE_CONFIG).ok(); if let Some(_config) = storage_config { config["storage_config"] = serde_json::from_str(&_config).unwrap(); } @@ -276,14 +284,14 @@ pub fn get_wallet_credentials(storage_creds: Option<&str>) -> String { credentials.to_string() } -pub fn validate_payment_method() -> Result<(), u32> { +pub fn validate_payment_method() -> VcxResult<()> { let config = SETTINGS.read().unwrap(); if let Some(method) = config.get(CONFIG_PAYMENT_METHOD) { if !method.to_string().is_empty() { return Ok(()); } } - return Err(error::MISSING_PAYMENT_METHOD.code_num); + return Err(VcxError::from(VcxErrorKind::MissingPaymentMethod)); } pub fn get_payment_method() -> String { @@ -332,22 +340,25 @@ pub fn get_protocol_type() -> ProtocolTypes { ProtocolTypes::from(get_config_value(CONFIG_PROTOCOL_TYPE).unwrap_or(DEFAULT_PROTOCOL_TYPE.to_string())) } -pub fn write_config_to_file(config: &str, path_string: &str) -> Result<(), u32> { +pub fn write_config_to_file(config: &str, path_string: &str) -> VcxResult<()> { trace!("write_config_to_file >>> config: {}, path_string: {}", config, path_string); let mut file = fs::File::create(Path::new(path_string)) - .or(Err(error::UNKNOWN_ERROR.code_num))?; + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, err))?; - file.write_all(config.as_bytes()).or(Err(error::UNKNOWN_ERROR.code_num))?; + file.write_all(config.as_bytes()) + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, err))?; Ok(()) } -pub fn read_config_file(path: &str) -> Result { +pub fn read_config_file(path: &str) -> VcxResult { trace!("read_config_file >>> path: {}", path); - let mut file = fs::File::open(path).or(Err(error::UNKNOWN_ERROR.code_num))?; + let mut file = fs::File::open(path) + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, err))?; let mut config = String::new(); - file.read_to_string(&mut config).or(Err(error::UNKNOWN_ERROR.code_num))?; + file.read_to_string(&mut config) + .map_err(|err| VcxError::from_msg(VcxErrorKind::UnknownError, err))?; Ok(config) } @@ -375,7 +386,7 @@ pub mod tests { #[test] fn test_bad_path() { let path = "garbage.txt"; - assert_eq!(process_config_file(&path), Err(error::INVALID_CONFIGURATION.code_num)); + assert_eq!(process_config_file(&path).unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); } #[test] @@ -399,7 +410,7 @@ pub mod tests { }).to_string(); write_config_to_file(&content, config_path).unwrap(); - assert_eq!(read_config_file(config_path), Ok(content)); + assert_eq!(read_config_file(config_path).unwrap(), content); } #[test] @@ -423,7 +434,7 @@ pub mod tests { }).to_string(); write_config_to_file(&content, config_path).unwrap(); - assert_eq!(process_config_file(config_path), Ok(error::SUCCESS.code_num)); + assert_eq!(process_config_file(config_path).unwrap(), error::SUCCESS.code_num); assert_eq!(get_config_value("institution_name").unwrap(), "evernym enterprise".to_string()); } @@ -445,7 +456,7 @@ pub mod tests { "wallet_key":"key" }).to_string(); - assert_eq!(process_config_string(&content), Ok(error::SUCCESS.code_num)); + assert_eq!(process_config_string(&content).unwrap(), error::SUCCESS.code_num); } #[test] @@ -467,7 +478,7 @@ pub mod tests { "institution_verkey": "444MFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", }).to_string(); let config: HashMap = serde_json::from_str(&content).unwrap(); - assert_eq!(validate_config(&config), Ok(error::SUCCESS.code_num)); + assert_eq!(validate_config(&config).unwrap(), error::SUCCESS.code_num); } #[test] @@ -477,51 +488,51 @@ pub mod tests { let valid_ver = DEFAULT_VERKEY; let mut config: HashMap = HashMap::new(); - assert_eq!(validate_config(&config), Err(error::MISSING_WALLET_KEY.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::MissingWalletKey); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_INSTITUTION_DID.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_DID.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidDid); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_INSTITUTION_VERKEY.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_VERKEY.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidVerkey); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_AGENCY_DID.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_DID.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidDid); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_AGENCY_VERKEY.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_VERKEY.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidVerkey); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_SDK_TO_REMOTE_DID.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_DID.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidDid); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_SDK_TO_REMOTE_VERKEY.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_VERKEY.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidVerkey); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_REMOTE_TO_SDK_DID.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_DID.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidDid); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_SDK_TO_REMOTE_VERKEY.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_VERKEY.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidVerkey); config.drain(); config.insert(CONFIG_WALLET_KEY.to_string(), "password".to_string()); config.insert(CONFIG_INSTITUTION_LOGO_URL.to_string(), invalid.to_string()); - assert_eq!(validate_config(&config), Err(error::INVALID_URL.code_num)); + assert_eq!(validate_config(&config).unwrap_err().kind(), VcxErrorKind::InvalidUrl); config.drain(); } @@ -533,17 +544,17 @@ pub mod tests { config.insert("invalid".to_string(), "invalid_url".to_string()); //Success - assert_eq!(validate_optional_config_val(config.get("valid"), error::INVALID_URL.code_num, closure), - Ok(error::SUCCESS.code_num)); + assert_eq!(validate_optional_config_val(config.get("valid"), VcxErrorKind::InvalidUrl, closure).unwrap(), + error::SUCCESS.code_num); // Success with No config - assert_eq!(validate_optional_config_val(config.get("unknown"), error::INVALID_URL.code_num, closure), - Ok(error::SUCCESS.code_num)); + assert_eq!(validate_optional_config_val(config.get("unknown"), VcxErrorKind::InvalidUrl, closure).unwrap(), + error::SUCCESS.code_num); // Fail with failed fn call assert_eq!(validate_optional_config_val(config.get("invalid"), - error::INVALID_URL.code_num, - closure), Err(error::INVALID_URL.code_num)); + VcxErrorKind::InvalidUrl, + closure).unwrap_err().kind(), VcxErrorKind::InvalidUrl); } #[test] @@ -552,7 +563,7 @@ pub mod tests { let value1 = "value1".to_string(); // Fails with invalid key - assert_eq!(get_config_value(&key), Err(error::INVALID_CONFIGURATION.code_num)); + assert_eq!(get_config_value(&key).unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); set_config_value(&key, &value1); assert_eq!(get_config_value(&key).unwrap(), value1); @@ -562,20 +573,20 @@ pub mod tests { fn test_payment_plugin_validation() { clear_config(); set_config_value(CONFIG_PAYMENT_METHOD, "null"); - assert_eq!(validate_payment_method(), Ok(())); + assert_eq!(validate_payment_method().unwrap(), ()); } #[test] fn test_payment_plugin_validation_empty_string() { clear_config(); set_config_value(CONFIG_PAYMENT_METHOD, ""); - assert_eq!(validate_payment_method(), Err(error::MISSING_PAYMENT_METHOD.code_num)); + assert_eq!(validate_payment_method().unwrap_err().kind(), VcxErrorKind::MissingPaymentMethod); } #[test] fn test_payment_plugin_validation_missing_option() { clear_config(); - assert_eq!(validate_payment_method(), Err(error::MISSING_PAYMENT_METHOD.code_num)); + assert_eq!(validate_payment_method().unwrap_err().kind(), VcxErrorKind::MissingPaymentMethod); } #[test] @@ -589,7 +600,7 @@ pub mod tests { "wallet_key":"key", }).to_string(); - assert_eq!(process_config_string(&content), Ok(error::SUCCESS.code_num)); + assert_eq!(process_config_string(&content).unwrap(), error::SUCCESS.code_num); assert_eq!(get_config_value("pool_name").unwrap(), "pool1".to_string()); assert_eq!(get_config_value("config_name").unwrap(), "config1".to_string()); @@ -601,11 +612,11 @@ pub mod tests { clear_config(); // Fails after config is cleared - assert_eq!(get_config_value("pool_name"), Err(error::INVALID_CONFIGURATION.code_num)); - assert_eq!(get_config_value("config_name"), Err(error::INVALID_CONFIGURATION.code_num)); - assert_eq!(get_config_value("wallet_name"), Err(error::INVALID_CONFIGURATION.code_num)); - assert_eq!(get_config_value("institution_name"), Err(error::INVALID_CONFIGURATION.code_num)); - assert_eq!(get_config_value("genesis_path"), Err(error::INVALID_CONFIGURATION.code_num)); - assert_eq!(get_config_value("wallet_key"), Err(error::INVALID_CONFIGURATION.code_num)); + assert_eq!(get_config_value("pool_name").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); + assert_eq!(get_config_value("config_name").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); + assert_eq!(get_config_value("wallet_name").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); + assert_eq!(get_config_value("institution_name").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); + assert_eq!(get_config_value("genesis_path").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); + assert_eq!(get_config_value("wallet_key").unwrap_err().kind(), VcxErrorKind::InvalidConfiguration); } } diff --git a/vcx/libvcx/src/utils/ccallback.rs b/vcx/libvcx/src/utils/ccallback.rs index ba5cf3cf31..4d82dd0f57 100644 --- a/vcx/libvcx/src/utils/ccallback.rs +++ b/vcx/libvcx/src/utils/ccallback.rs @@ -2,7 +2,7 @@ macro_rules! check_useful_c_callback { ($x:ident, $e:expr) => { let $x = match $x { Some($x) => $x, - None => return $e + None => return VcxError::from_msg($e, "Invalid callback has been passed").into() }; } } \ No newline at end of file diff --git a/vcx/libvcx/src/utils/cstring.rs b/vcx/libvcx/src/utils/cstring.rs index 823a446a50..57666749fe 100644 --- a/vcx/libvcx/src/utils/cstring.rs +++ b/vcx/libvcx/src/utils/cstring.rs @@ -1,6 +1,4 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use std::ffi::CStr; use std::str::Utf8Error; @@ -43,11 +41,11 @@ macro_rules! check_useful_c_str { ($x:ident, $e:expr) => { let $x = match CStringUtils::c_str_to_string($x) { Ok(Some(val)) => val, - _ => return $e, + _ => return VcxError::from_msg($e, "Invalid pointer has been passed").into() }; if $x.is_empty() { - return $e + return VcxError::from_msg($e, "Empty string has been passed").into() } } } @@ -56,7 +54,7 @@ macro_rules! check_useful_opt_c_str { ($x:ident, $e:expr) => { let $x = match CStringUtils::c_str_to_string($x) { Ok(opt_val) => opt_val, - Err(_) => return $e + Err(_) => return VcxError::from_msg($e, "Invalid pointer has been passed").into() }; } } @@ -65,11 +63,11 @@ macro_rules! check_useful_opt_c_str { macro_rules! check_useful_c_byte_array { ($ptr:ident, $len:expr, $err1:expr, $err2:expr) => { if $ptr.is_null() { - return $err1; + return VcxError::from_msg($err1, "Invalid pointer has been passed").into() } if $len <= 0 { - return $err2; + return VcxError::from_msg($err2, "Array length must be greater than 0").into() } let $ptr = unsafe { $crate::std::slice::from_raw_parts($ptr, $len as usize) }; diff --git a/vcx/libvcx/src/utils/error.rs b/vcx/libvcx/src/utils/error.rs index 3f175f0ee4..f298e8af34 100644 --- a/vcx/libvcx/src/utils/error.rs +++ b/vcx/libvcx/src/utils/error.rs @@ -265,15 +265,6 @@ pub fn error_string(code_num:u32) -> String { } } -pub fn map_libindy_err(check_rtn: u32, default_rtn: u32) -> u32 { - match check_rtn { - x if x == TIMEOUT_LIBINDY_ERROR.code_num => { - x - }, - _ => default_rtn - } -} - #[cfg(test)] mod tests { use super::*; @@ -434,21 +425,4 @@ mod tests { fn test_invalid_master_secret() { assert_eq!(error_message(&INVALID_MASTER_SECRET.code_num), INVALID_MASTER_SECRET.message); } - - #[test] - fn test_map_libindy_err() { - let default = UNKNOWN_ERROR.code_num; - // Pass in arbitrary check val, rtn default err - assert_eq!(map_libindy_err(INVALID_SCHEMA_SEQ_NO.code_num, default), - default); - // Pass libindy timeout, rtn Err(libindy timeout) - assert_eq!(map_libindy_err(TIMEOUT_LIBINDY_ERROR.code_num, default), - TIMEOUT_LIBINDY_ERROR.code_num); - - let fn_map_err = |x: Result| x; - // map_libindy_err not called with Ok returned - assert_eq!(fn_map_err(Ok(0)).map_err(|x| map_libindy_err(x, default)), Ok(0)); - // map_libindy_err called with Err returned - assert_eq!(fn_map_err(Err(0)).map_err(|x| map_libindy_err(x, default)), Err(default)) - } } diff --git a/vcx/libvcx/src/utils/httpclient.rs b/vcx/libvcx/src/utils/httpclient.rs index e157720df0..087e60acfb 100644 --- a/vcx/libvcx/src/utils/httpclient.rs +++ b/vcx/libvcx/src/utils/httpclient.rs @@ -4,14 +4,15 @@ use std::sync::Mutex; use reqwest; use reqwest::header::CONTENT_TYPE; use std::env; +use error::prelude::*; lazy_static! { static ref NEXT_U8_RESPONSE: Mutex>> = Mutex::new(vec![]); } //Todo: change this RC to a u32 -pub fn post_u8(body_content: &Vec) -> Result, &'static str> { - let endpoint = settings::get_config_value(settings::CONFIG_AGENCY_ENDPOINT).or(Err("Invalid Configuration"))?; +pub fn post_u8(body_content: &Vec) -> VcxResult> { + let endpoint = settings::get_config_value(settings::CONFIG_AGENCY_ENDPOINT)?; let url = format!("{}/agency/msg", endpoint); if settings::test_agency_mode_enabled() { @@ -23,7 +24,8 @@ pub fn post_u8(body_content: &Vec) -> Result, &'static str> { info!("::Android code"); set_ssl_cert_location(); } - let client = reqwest::ClientBuilder::new().timeout(::utils::timeout::TimeoutUtils::long_timeout()).build().or(Err("Preparing Post failed"))?; + let client = reqwest::ClientBuilder::new().timeout(::utils::timeout::TimeoutUtils::long_timeout()).build() + .or(Err(VcxError::from_msg(VcxErrorKind::PostMessageFailed, "Preparing Post failed")))?; debug!("Posting encrypted bundle to: \"{}\"", url); let mut response = @@ -33,7 +35,7 @@ pub fn post_u8(body_content: &Vec) -> Result, &'static str> { .send() .map_err(|err| { error!("error: {}", err); - "Could not connect" + VcxError::from_msg(VcxErrorKind::PostMessageFailed, "Could not connect") })?; trace!("Response Header: {:?}", response); @@ -43,11 +45,12 @@ pub fn post_u8(body_content: &Vec) -> Result, &'static str> { Ok(x) => info!("Request failed: {}", content), Err(x) => info!("could not read response"), }; - return Err("POST failed"); + return Err(VcxError::from_msg(VcxErrorKind::PostMessageFailed, format!("POST failed with: {}", content))); } let mut content = Vec::new(); - response.read_to_end(&mut content).or(Err("could not read response"))?; + response.read_to_end(&mut content) + .or(Err(VcxError::from_msg(VcxErrorKind::PostMessageFailed, "could not read response")))?; Ok(content) } diff --git a/vcx/libvcx/src/utils/json.rs b/vcx/libvcx/src/utils/json.rs index 7b0434d5eb..46c827df12 100644 --- a/vcx/libvcx/src/utils/json.rs +++ b/vcx/libvcx/src/utils/json.rs @@ -1,26 +1,10 @@ extern crate serde; extern crate serde_json; -use self::serde::{Serialize, Deserialize}; -use self::serde_json::Error; use serde_json::Value; use serde_json::Map; use std::string::String; -use utils::error; - - -pub trait JsonEncodable: Serialize + Sized { - fn to_json(&self) -> Result { - serde_json::to_string(self) - } -} - -pub trait JsonDecodable<'a>: Deserialize<'a> { - fn from_json(to_stringd: &'a str) -> Result { - serde_json::from_str(to_stringd) - } -} - +use error::prelude::*; pub trait KeyMatch { fn matches(&self, key: &String, context: &Vec) -> bool; @@ -36,20 +20,20 @@ impl KeyMatch for String { Rewrites keys in a serde value structor to new mapped values. Returns the remapped value. Leaves unmapped keys as they are. */ -pub fn mapped_key_rewrite(val: Value, remap: &Vec<(T, String)>) -> Result { +pub fn mapped_key_rewrite(val: Value, remap: &Vec<(T, String)>) -> VcxResult { let mut context: Vec = Default::default(); _mapped_key_rewrite(val, &mut context, remap) } -fn _mapped_key_rewrite(val: Value, context: &mut Vec, remap: &Vec<(T, String)>) -> Result { +fn _mapped_key_rewrite(val: Value, context: &mut Vec, remap: &Vec<(T, String)>) -> VcxResult { if let Value::Object(mut map) = val { let mut keys:Vec = _collect_keys(&map); while let Some(k) = keys.pop() { let mut value = map.remove(&k).ok_or_else(||{ warn!("Unexpected key value mutation"); - error::INVALID_JSON.code_num + VcxError::from_msg(VcxErrorKind::InvalidJson, "Unexpected key value mutation") })?; diff --git a/vcx/libvcx/src/utils/libindy/anoncreds.rs b/vcx/libvcx/src/utils/libindy/anoncreds.rs index 6d4821cc8f..6f1db1815a 100644 --- a/vcx/libvcx/src/utils/libindy/anoncreds.rs +++ b/vcx/libvcx/src/utils/libindy/anoncreds.rs @@ -1,27 +1,25 @@ -extern crate libc; - use futures::Future; use serde_json; -use serde_json::{ map::Map, Value}; +use serde_json::{map::Map, Value}; +use indy::{anoncreds, blob_storage, ledger}; +use time; + use settings; -use utils::constants::{ LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, ATTRS, REV_STATE_JSON}; -use utils::error::{ INVALID_PROOF_REQUEST, INVALID_ATTRIBUTES_STRUCTURE, INVALID_CONFIGURATION, INVALID_JSON, DUPLICATE_SCHEMA, UNKNOWN_SCHEMA_REJECTION } ; -use utils::libindy::{ error_codes::map_rust_indy_sdk_error, mock_libindy_rc, wallet::get_wallet_handle }; +use utils::constants::{LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, ATTRS, REV_STATE_JSON}; +use utils::libindy::{error_codes::map_rust_indy_sdk_error, mock_libindy_rc, wallet::get_wallet_handle}; use utils::libindy::payments::{pay_for_txn, PaymentTxn}; -use utils::constants::{ SCHEMA_ID, SCHEMA_JSON, SCHEMA_TXN_TYPE, CRED_DEF_ID, CRED_DEF_JSON, CRED_DEF_TXN_TYPE, REV_REG_DEF_TXN_TYPE, REV_REG_DELTA_TXN_TYPE, REVOC_REG_TYPE, rev_def_json, REV_REG_ID, REV_REG_DELTA_JSON, REV_REG_JSON}; -use utils::libindy::ledger::{libindy_build_schema_request, libindy_build_get_schema_request, libindy_submit_request, libindy_parse_get_cred_def_response, libindy_parse_get_schema_response, libindy_build_create_credential_def_txn, libindy_build_get_credential_def_txn}; -use indy::anoncreds; -use indy::blob_storage; -use indy::ledger; -use time; +use utils::libindy::ledger::*; +use utils::constants::{SCHEMA_ID, SCHEMA_JSON, SCHEMA_TXN_TYPE, CRED_DEF_ID, CRED_DEF_JSON, CRED_DEF_TXN_TYPE, REV_REG_DEF_TXN_TYPE, REV_REG_DELTA_TXN_TYPE, REVOC_REG_TYPE, rev_def_json, REV_REG_ID, REV_REG_DELTA_JSON, REV_REG_JSON}; +use error::prelude::*; + +const BLOB_STORAGE_TYPE: &str = "default"; pub fn libindy_verifier_verify_proof(proof_req_json: &str, proof_json: &str, schemas_json: &str, credential_defs_json: &str, rev_reg_defs_json: &str, - rev_regs_json: &str) -> Result { - + rev_regs_json: &str) -> VcxResult { //TODO there was timeout here (before future-based Rust wrapper) anoncreds::verifier_verify_proof(proof_req_json, proof_json, @@ -33,25 +31,27 @@ pub fn libindy_verifier_verify_proof(proof_req_json: &str, .map_err(map_rust_indy_sdk_error) } -pub fn libindy_create_and_store_revoc_reg(issuer_did: &str, cred_def_id: &str, tails_path: &str, max_creds: u32) -> Result<(String, String, String), u32> { +pub fn libindy_create_and_store_revoc_reg(issuer_did: &str, cred_def_id: &str, tails_path: &str, max_creds: u32) -> VcxResult<(String, String, String)> { trace!("creating revocation: {}, {}, {}", cred_def_id, tails_path, max_creds); + let tails_config = json!({"base_dir": tails_path,"uri_pattern": ""}).to_string(); - let writer = blob_storage::open_writer("default", &tails_config.to_string()) + + let writer = blob_storage::open_writer(BLOB_STORAGE_TYPE, &tails_config) .wait() - .map_err(|ec|map_rust_indy_sdk_error(ec))?; + .map_err(map_rust_indy_sdk_error)?; + let revoc_config = json!({"max_cred_num": max_creds,"issuance_type": "ISSUANCE_BY_DEFAULT"}).to_string(); anoncreds::issuer_create_and_store_revoc_reg(get_wallet_handle(), issuer_did, None, "tag1", cred_def_id, &revoc_config, writer) .wait() - .map_err(|ec|map_rust_indy_sdk_error(ec)) + .map_err(map_rust_indy_sdk_error) } pub fn libindy_create_and_store_credential_def(issuer_did: &str, schema_json: &str, tag: &str, sig_type: Option<&str>, - config_json: &str) -> Result<(String, String), u32> { - + config_json: &str) -> VcxResult<(String, String)> { anoncreds::issuer_create_and_store_credential_def(get_wallet_handle(), issuer_did, schema_json, @@ -62,14 +62,21 @@ pub fn libindy_create_and_store_credential_def(issuer_did: &str, .map_err(map_rust_indy_sdk_error) } -pub fn libindy_issuer_create_credential_offer(cred_def_id: &str) -> Result { +pub fn libindy_issuer_create_credential_offer(cred_def_id: &str) -> VcxResult { if settings::test_indy_mode_enabled() { let rc = mock_libindy_rc(); - if rc != 0 { return Err(rc) }; + if rc != 0 { return Err(VcxError::from(VcxErrorKind::InvalidState)); }; return Ok(LIBINDY_CRED_OFFER.to_string()); } anoncreds::issuer_create_credential_offer(get_wallet_handle(), - cred_def_id) + cred_def_id) + .wait() + .map_err(map_rust_indy_sdk_error) +} + +fn blob_storage_open_reader(base_dir: &str) -> VcxResult { + let tails_config = json!({"base_dir": base_dir,"uri_pattern": ""}).to_string(); + blob_storage::open_reader("default", &tails_config) .wait() .map_err(map_rust_indy_sdk_error) } @@ -78,17 +85,11 @@ pub fn libindy_issuer_create_credential(cred_offer_json: &str, cred_req_json: &str, cred_values_json: &str, rev_reg_id: Option, - tails_file: Option) -> Result<(String, Option, Option), u32>{ - + tails_file: Option) -> VcxResult<(String, Option, Option)> { let revocation = rev_reg_id.as_ref().map(String::as_str); let blob_handle = match tails_file { - Some(x) => { - let tails_config = json!({"base_dir": x,"uri_pattern": ""}).to_string(); - blob_storage::open_reader("default", &tails_config.to_string()) - .wait() - .map_err(map_rust_indy_sdk_error)? - }, + Some(x) => blob_storage_open_reader(&x)?, None => -1, }; anoncreds::issuer_create_credential(get_wallet_handle(), @@ -106,7 +107,7 @@ pub fn libindy_prover_create_proof(proof_req_json: &str, master_secret_id: &str, schemas_json: &str, credential_defs_json: &str, - revoc_states_json: Option<&str>) -> Result { + revoc_states_json: Option<&str>) -> VcxResult { let revoc_states_json = revoc_states_json.unwrap_or("{}"); anoncreds::prover_create_proof(get_wallet_handle(), proof_req_json, @@ -119,96 +120,92 @@ pub fn libindy_prover_create_proof(proof_req_json: &str, .map_err(map_rust_indy_sdk_error) } -fn fetch_credentials(search_handle: i32, requested_attributes: Map) -> Result { +fn fetch_credentials(search_handle: i32, requested_attributes: Map) -> VcxResult { let mut v: Value = json!({}); for item_referent in requested_attributes.keys().into_iter() { - v[ATTRS][item_referent] = serde_json::from_str(&anoncreds::prover_fetch_credentials_for_proof_req(search_handle, item_referent, 100).wait() - .map_err(map_rust_indy_sdk_error)?) - .map_err(|_| { - error!("Invalid Json Parsing of Object Returned from Libindy. Did Libindy change its structure?"); - INVALID_CONFIGURATION.code_num - })? + v[ATTRS][item_referent] = + serde_json::from_str(&anoncreds::prover_fetch_credentials_for_proof_req(search_handle, item_referent, 100).wait() + .map_err(map_rust_indy_sdk_error)?) + .map_err(|_| { + error!("Invalid Json Parsing of Object Returned from Libindy. Did Libindy change its structure?"); + VcxError::from_msg(VcxErrorKind::InvalidConfiguration, "Invalid Json Parsing of Object Returned from Libindy. Did Libindy change its structure?") + })? } + Ok(v.to_string()) } -fn close_search_handle(search_handle: i32) -> Result<(), u32> { - anoncreds::prover_close_credentials_search_for_proof_req(search_handle).wait().map_err(|ec| { - error!("Error closing search handle"); - map_rust_indy_sdk_error(ec) - }) +fn close_search_handle(search_handle: i32) -> VcxResult<()> { + anoncreds::prover_close_credentials_search_for_proof_req(search_handle) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn libindy_prover_get_credentials_for_proof_req(proof_req: &str) -> Result { +pub fn libindy_prover_get_credentials_for_proof_req(proof_req: &str) -> VcxResult { let wallet_handle = get_wallet_handle(); // this may be too redundant since Prover::search_credentials will validate the proof reqeuest already. - let proof_request_json:Map = serde_json::from_str(proof_req).map_err(|_| INVALID_PROOF_REQUEST.code_num)?; + let proof_request_json: Map = serde_json::from_str(proof_req) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidProofRequest, format!("Cannot deserialize ProofRequest")))?; // since the search_credentials_for_proof request validates that the proof_req is properly structured, this get() // fn should never fail, unless libindy changes their formats. - let requested_attributes:Option> = proof_request_json.get(REQUESTED_ATTRIBUTES).and_then(|v| { - serde_json::from_value(v.clone()).map_err(|_| { - error!("Invalid Json Parsing of Requested Attributes Retrieved From Libindy. Did Libindy change its structure?"); - }).ok() - }); + let requested_attributes: Option> = proof_request_json.get(REQUESTED_ATTRIBUTES) + .and_then(|v| { + serde_json::from_value(v.clone()) + .map_err(|_| { + error!("Invalid Json Parsing of Requested Attributes Retrieved From Libindy. Did Libindy change its structure?"); + }).ok() + }); match requested_attributes { Some(attrs) => { let search_handle = anoncreds::prover_search_credentials_for_proof_req(wallet_handle, proof_req, None) .wait() - .map_err(|ec| { - error!("Opening Indy Search for Credentials Failed"); - map_rust_indy_sdk_error(ec) - })?; + .map_err(map_rust_indy_sdk_error)?; let creds: String = fetch_credentials(search_handle, attrs)?; // should an error on closing a search handle throw an error, or just a warning? // for now we're are just outputting to the user that there is an issue, and continuing on. let _ = close_search_handle(search_handle); Ok(creds) - }, + } None => { - Err(INVALID_ATTRIBUTES_STRUCTURE.code_num) + Err(VcxError::from_msg(VcxErrorKind::InvalidAttributesStructure, "Invalid Json Parsing of Requested Attributes Retrieved From Libindy")) } } - } pub fn libindy_prover_create_credential_req(prover_did: &str, credential_offer_json: &str, - credential_def_json: &str) -> Result<(String, String), u32> { + credential_def_json: &str) -> VcxResult<(String, String)> { if settings::test_indy_mode_enabled() { return Ok((::utils::constants::CREDENTIAL_REQ_STRING.to_owned(), String::new())); } let master_secret_name = settings::DEFAULT_LINK_SECRET_ALIAS; anoncreds::prover_create_credential_req(get_wallet_handle(), - prover_did, - credential_offer_json, - credential_def_json, - master_secret_name) + prover_did, + credential_offer_json, + credential_def_json, + master_secret_name) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_prover_create_revocation_state(rev_reg_def_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> Result { +pub fn libindy_prover_create_revocation_state(rev_reg_def_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(REV_STATE_JSON.to_string()); } - let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); - let blob_handle = blob_storage::open_reader("default", &tails_config.to_string()) - .wait() - .map_err(|ec|map_rust_indy_sdk_error(ec))?; - anoncreds::create_revocation_state(blob_handle, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) + let blob_handle = blob_storage_open_reader(tails_file)?; + + anoncreds::create_revocation_state(blob_handle, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_prover_update_revocation_state(rev_reg_def_json: &str, rev_state_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> Result { +pub fn libindy_prover_update_revocation_state(rev_reg_def_json: &str, rev_state_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(REV_STATE_JSON.to_string()); } - let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); - let blob_handle = blob_storage::open_reader("default", &tails_config.to_string()) - .wait() - .map_err(|ec|map_rust_indy_sdk_error(ec))?; - anoncreds::update_revocation_state(blob_handle, rev_state_json, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) + let blob_handle = blob_storage_open_reader(tails_file)?; + + anoncreds::update_revocation_state(blob_handle, rev_state_json, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) .wait() .map_err(map_rust_indy_sdk_error) } @@ -217,26 +214,24 @@ pub fn libindy_prover_store_credential(cred_id: Option<&str>, cred_req_meta: &str, cred_json: &str, cred_def_json: &str, - rev_reg_def_json: Option) -> Result { + rev_reg_def_json: Option<&str>) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok("cred_id".to_string()); } - let revocation = rev_reg_def_json.as_ref().map(String::as_str); - anoncreds::prover_store_credential(get_wallet_handle(), - cred_id, - cred_req_meta, - cred_json, - cred_def_json, - revocation) + cred_id, + cred_req_meta, + cred_json, + cred_def_json, + rev_reg_def_json) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_prover_create_master_secret(master_secret_id: &str) -> Result { +pub fn libindy_prover_create_master_secret(master_secret_id: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(settings::DEFAULT_LINK_SECRET_ALIAS.to_string()); } anoncreds::prover_create_master_secret(get_wallet_handle(), - Some(master_secret_id)) + Some(master_secret_id)) .wait() .map_err(map_rust_indy_sdk_error) } @@ -244,22 +239,17 @@ pub fn libindy_prover_create_master_secret(master_secret_id: &str) -> Result Result<(String, String), u32>{ - + attrs: &str) -> VcxResult<(String, String)> { anoncreds::issuer_create_schema(issuer_did, - name, - version, - attrs) + name, + version, + attrs) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_issuer_revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) -> Result { - - let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); - let blob_handle = blob_storage::open_reader("default", &tails_config) - .wait() - .map_err(map_rust_indy_sdk_error)?; +pub fn libindy_issuer_revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) -> VcxResult { + let blob_handle = blob_storage_open_reader(tails_file)?; anoncreds::issuer_revoke_credential(get_wallet_handle(), blob_handle, rev_reg_id, cred_rev_id) .wait() @@ -267,7 +257,7 @@ pub fn libindy_issuer_revoke_credential(tails_file: &str, rev_reg_id: &str, cred } pub fn libindy_build_revoc_reg_def_request(submitter_did: &str, - rev_reg_def_json: &str) -> Result { + rev_reg_def_json: &str) -> VcxResult { ledger::build_revoc_reg_def_request(submitter_did, rev_reg_def_json) .wait() .map_err(map_rust_indy_sdk_error) @@ -276,19 +266,19 @@ pub fn libindy_build_revoc_reg_def_request(submitter_did: &str, pub fn libindy_build_revoc_reg_entry_request(submitter_did: &str, rev_reg_id: &str, rev_def_type: &str, - value: &str) -> Result { + value: &str) -> VcxResult { ledger::build_revoc_reg_entry_request(submitter_did, rev_reg_id, rev_def_type, value) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_build_get_revoc_reg_def_request(submitter_did: &str, rev_reg_id: &str) -> Result { +pub fn libindy_build_get_revoc_reg_def_request(submitter_did: &str, rev_reg_id: &str) -> VcxResult { ledger::build_get_revoc_reg_def_request(Some(submitter_did), rev_reg_id) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_parse_get_revoc_reg_def_response(rev_reg_def_json: &str) -> Result<(String, String), u32> { +pub fn libindy_parse_get_revoc_reg_def_response(rev_reg_def_json: &str) -> VcxResult<(String, String)> { ledger::parse_get_revoc_reg_def_response(rev_reg_def_json) .wait() .map_err(map_rust_indy_sdk_error) @@ -297,7 +287,7 @@ pub fn libindy_parse_get_revoc_reg_def_response(rev_reg_def_json: &str) -> Resul pub fn libindy_build_get_revoc_reg_delta_request(submitter_did: &str, rev_reg_id: &str, from: i64, - to: i64) -> Result { + to: i64) -> VcxResult { ledger::build_get_revoc_reg_delta_request(Some(submitter_did), rev_reg_id, from, @@ -306,8 +296,7 @@ pub fn libindy_build_get_revoc_reg_delta_request(submitter_did: &str, .map_err(map_rust_indy_sdk_error) } -fn libindy_build_get_revoc_reg_request(submitter_did: &str, rev_reg_id: &str, timestamp: u64) - -> Result { +fn libindy_build_get_revoc_reg_request(submitter_did: &str, rev_reg_id: &str, timestamp: u64) -> VcxResult { ledger::build_get_revoc_reg_request(Some(submitter_did), rev_reg_id, timestamp as i64) @@ -315,22 +304,24 @@ fn libindy_build_get_revoc_reg_request(submitter_did: &str, rev_reg_id: &str, ti .map_err(map_rust_indy_sdk_error) } -fn libindy_parse_get_revoc_reg_response(get_rev_reg_resp: &str) -> Result<(String, String, u64), u32> { +fn libindy_parse_get_revoc_reg_response(get_rev_reg_resp: &str) -> VcxResult<(String, String, u64)> { ledger::parse_get_revoc_reg_response(get_rev_reg_resp) .wait() .map_err(map_rust_indy_sdk_error) } pub fn libindy_parse_get_revoc_reg_delta_response(get_rev_reg_delta_response: &str) - -> Result<(String, String, u64), u32> { + -> VcxResult<(String, String, u64)> { ledger::parse_get_revoc_reg_delta_response(get_rev_reg_delta_response) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn create_schema(name: &str, version: &str, data: &str) -> Result<(String, Option), u32> { +pub fn create_schema(name: &str, version: &str, data: &str) -> VcxResult<(String, Option)> { if settings::test_indy_mode_enabled() { - return Ok((SCHEMA_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap(), ))); + let inputs = vec!["pay:null:9UFgyjuJxi1i1HD".to_string()]; + let outputs = serde_json::from_str::>(r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#).unwrap(); + return Ok((SCHEMA_ID.to_string(), Some(PaymentTxn::from_parts(inputs, outputs, 1, false)))); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; @@ -341,32 +332,16 @@ pub fn create_schema(name: &str, version: &str, data: &str) -> Result<(String, O let (payment, response) = pay_for_txn(&request, SCHEMA_TXN_TYPE)?; - _check_create_schema_response(&response)?; + _check_schema_response(&response)?; Ok((id, payment)) } -fn _check_create_schema_response(response: &str) -> Result<(), u32> { - let response: Value = serde_json::from_str(response).or(Err(INVALID_JSON.code_num))?; - - if let Some(_) = response.get("result") { return Ok(()) }; - - warn!("No result found in ledger txn. Must be Rejected"); - - if response["op"] == json!("REJECT") { - match response.get("reason") { - Some(r) => return Err(DUPLICATE_SCHEMA.code_num), - None => return Err(UNKNOWN_SCHEMA_REJECTION.code_num), - } - } - - Err(UNKNOWN_SCHEMA_REJECTION.code_num) -} - -pub fn get_schema_json(schema_id: &str) -> Result<(String, String), u32> { - if settings::test_indy_mode_enabled() { return Ok((SCHEMA_ID.to_string(), SCHEMA_JSON.to_string()))} +pub fn get_schema_json(schema_id: &str) -> VcxResult<(String, String)> { + if settings::test_indy_mode_enabled() { return Ok((SCHEMA_ID.to_string(), SCHEMA_JSON.to_string())); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + libindy_build_get_schema_request(&submitter_did, schema_id) .and_then(|req| libindy_submit_request(&req)) .and_then(|response| libindy_parse_get_schema_response(&response)) @@ -376,9 +351,11 @@ pub fn create_cred_def(issuer_did: &str, schema_json: &str, tag: &str, sig_type: Option<&str>, - support_revocation: Option) -> Result<(String, Option), u32> { + support_revocation: Option) -> VcxResult<(String, Option)> { if settings::test_indy_mode_enabled() { - return Ok((CRED_DEF_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()))); + let inputs = vec!["pay:null:9UFgyjuJxi1i1HD".to_string()]; + let outputs = serde_json::from_str::>(r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#).unwrap(); + return Ok((CRED_DEF_ID.to_string(), Some(PaymentTxn::from_parts(inputs, outputs, 1, false)))); } let config_json = json!({"support_revocation": support_revocation.unwrap_or(false)}).to_string(); @@ -396,7 +373,7 @@ pub fn create_cred_def(issuer_did: &str, Ok((id, payment)) } -pub fn get_cred_def_json(cred_def_id: &str) -> Result<(String, String), u32> { +pub fn get_cred_def_json(cred_def_id: &str) -> VcxResult<(String, String)> { if settings::test_indy_mode_enabled() { return Ok((CRED_DEF_ID.to_string(), CRED_DEF_JSON.to_string())); } libindy_build_get_credential_def_txn(cred_def_id) @@ -405,17 +382,16 @@ pub fn get_cred_def_json(cred_def_id: &str) -> Result<(String, String), u32> { } pub fn create_rev_reg_def(issuer_did: &str, cred_def_id: &str, tails_file: &str, max_creds: u32) - -> Result<(String, String, String, Option), u32> { + -> VcxResult<(String, String, String, Option)> { debug!("creating revocation registry definition with issuer_did: {}, cred_def_id: {}, tails_file_path: {}, max_creds: {}", issuer_did, cred_def_id, tails_file, max_creds); if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), rev_def_json(), "".to_string(), None)); } - let (rev_reg_id, rev_reg_def_json, rev_reg_entry_json) = libindy_create_and_store_revoc_reg( - issuer_did, - cred_def_id, - tails_file, - max_creds - )?; + let (rev_reg_id, rev_reg_def_json, rev_reg_entry_json) = + libindy_create_and_store_revoc_reg(issuer_did, + cred_def_id, + tails_file, + max_creds)?; let rev_reg_def_req = libindy_build_revoc_reg_def_request(issuer_did, &rev_reg_def_json)?; @@ -424,7 +400,7 @@ pub fn create_rev_reg_def(issuer_did: &str, cred_def_id: &str, tails_file: &str, Ok((rev_reg_id, rev_reg_def_json, rev_reg_entry_json, payment)) } -pub fn get_rev_reg_def_json(rev_reg_id: &str) -> Result<(String, String), u32> { +pub fn get_rev_reg_def_json(rev_reg_id: &str) -> VcxResult<(String, String)> { if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), rev_def_json())); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; @@ -435,13 +411,13 @@ pub fn get_rev_reg_def_json(rev_reg_id: &str) -> Result<(String, String), u32> { } pub fn post_rev_reg_delta(issuer_did: &str, rev_reg_id: &str, rev_reg_entry_json: &str) - -> Result<(Option, String), u32> { - libindy_build_revoc_reg_entry_request(issuer_did, rev_reg_id, REVOC_REG_TYPE, rev_reg_entry_json) - .and_then(|req| pay_for_txn(&req, REV_REG_DELTA_TXN_TYPE)) + -> VcxResult<(Option, String)> { + let request = libindy_build_revoc_reg_entry_request(issuer_did, rev_reg_id, REVOC_REG_TYPE, rev_reg_entry_json)?; + pay_for_txn(&request, REV_REG_DELTA_TXN_TYPE) } pub fn get_rev_reg_delta_json(rev_reg_id: &str, from: Option, to: Option) - -> Result<(String, String, u64), u32> { + -> VcxResult<(String, String, u64)> { if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), REV_REG_DELTA_JSON.to_string(), 1)); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; @@ -453,7 +429,7 @@ pub fn get_rev_reg_delta_json(rev_reg_id: &str, from: Option, to: Option Result<(String, String, u64), u32> { +pub fn get_rev_reg(rev_reg_id: &str, timestamp: u64) -> VcxResult<(String, String, u64)> { if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), REV_REG_JSON.to_string(), 1)); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; @@ -462,10 +438,11 @@ pub fn get_rev_reg(rev_reg_id: &str, timestamp: u64) -> Result<(String, String, .and_then(|response| libindy_parse_get_revoc_reg_response(&response)) } -pub fn revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) - -> Result<(Option, String), u32> { +pub fn revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) -> VcxResult<(Option, String)> { if settings::test_indy_mode_enabled() { - return Ok((Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()), REV_REG_DELTA_JSON.to_string())); + let inputs = vec!["pay:null:9UFgyjuJxi1i1HD".to_string()]; + let outputs = serde_json::from_str::>(r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#).unwrap(); + return Ok((Some(PaymentTxn::from_parts(inputs, outputs, 1, false)), REV_REG_DELTA_JSON.to_string())); } let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; @@ -476,22 +453,30 @@ pub fn revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) Ok((payment, delta)) } +fn _check_schema_response(response: &str) -> VcxResult<()> { + // TODO: saved backwardcampatibilyty but actually we can better handle response + match parse_response(response)? { + Response::Reply(_) => Ok(()), + Response::Reject(reject) => Err(VcxError::from_msg(VcxErrorKind::DuplicationSchema, format!("{:?}", reject))), + Response::ReqNACK(reqnack) => Err(VcxError::from_msg(VcxErrorKind::UnknownSchemaRejection, "Unknown Rejection of Schema Creation, refer to libindy documentation")) + } +} #[cfg(test)] pub mod tests { use super::*; use utils::get_temp_dir_path; + extern crate serde_json; extern crate rand; + use rand::Rng; use settings; use utils::constants::*; use std::thread; use std::time::Duration; #[cfg(feature = "pool_tests")] - use utils::error::LIBINDY_INVALID_STRUCTURE; - #[cfg(feature = "pool_tests")] - use utils::constants::{TEST_TAILS_FILE}; + use utils::constants::TEST_TAILS_FILE; pub fn create_schema(attr_list: &str) -> (String, String) { @@ -564,7 +549,6 @@ pub mod tests { } pub fn create_and_store_credential(attr_list: &str, revocation: bool) -> (String, String, String, String, String, String, String, String, Option, Option) { - let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, rev_reg_id) = create_credential_req(attr_list, revocation); /* create cred */ @@ -573,12 +557,11 @@ pub mod tests { let (rev_def_json, tails_file) = if revocation { let (id, json) = get_rev_reg_def_json(&rev_reg_id.clone().unwrap()).unwrap(); (Some(json), Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string().to_string())) - } else { (None, None) }; let (cred, cred_rev_id, _) = ::utils::libindy::anoncreds::libindy_issuer_create_credential(&offer, &req, &encoded_attributes, rev_reg_id.clone(), tails_file).unwrap(); /* store cred */ - let cred_id = ::utils::libindy::anoncreds::libindy_prover_store_credential(None, &req_meta, &cred, &cred_def_json, rev_def_json).unwrap(); + let cred_id = ::utils::libindy::anoncreds::libindy_prover_store_credential(None, &req_meta, &cred, &cred_def_json, rev_def_json.as_ref().map(String::as_str)).unwrap(); (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id, rev_reg_id, cred_rev_id) } @@ -628,7 +611,7 @@ pub mod tests { cred_def_id: cred_def_json, }).to_string(); - libindy_prover_get_credentials_for_proof_req(&proof_req).unwrap(); + libindy_prover_get_credentials_for_proof_req(&proof_req).unwrap(); let proof = libindy_prover_create_proof( &proof_req, @@ -670,7 +653,7 @@ pub mod tests { let schemas = json!({}).to_string(); let cred_defs = json!({}).to_string(); - libindy_prover_get_credentials_for_proof_req(&proof_req).unwrap(); + libindy_prover_get_credentials_for_proof_req(&proof_req).unwrap(); let proof = libindy_prover_create_proof( &proof_req, @@ -708,7 +691,7 @@ pub mod tests { init!("ledger"); let proof_req = "{"; let result = libindy_prover_get_credentials_for_proof_req(&proof_req); - assert_eq!(result.err(), Some(INVALID_PROOF_REQUEST.code_num)); + assert_eq!(result.unwrap_err().kind(), VcxErrorKind::InvalidProofRequest); let proof_req = json!({ "nonce":"123432421212", "name":"proof_req_1", @@ -726,14 +709,14 @@ pub mod tests { let result = libindy_prover_get_credentials_for_proof_req(&proof_req); let result_malformed_json = libindy_prover_get_credentials_for_proof_req("{}"); let wallet_handle = get_wallet_handle(); - let proof_req_str:String = serde_json::to_string(&proof_req).unwrap(); + let proof_req_str: String = serde_json::to_string(&proof_req).unwrap(); assert!(result.is_ok()); - assert_eq!(result_malformed_json.err(), Some(INVALID_ATTRIBUTES_STRUCTURE.code_num)); + assert_eq!(result_malformed_json.unwrap_err().kind(), VcxErrorKind::InvalidAttributesStructure); } #[cfg(feature = "pool_tests")] #[test] - fn test_issuer_revoke_credential(){ + fn test_issuer_revoke_credential() { init!("ledger"); let rc = libindy_issuer_revoke_credential(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap(), "", ""); assert!(rc.is_err()); @@ -748,7 +731,7 @@ pub mod tests { #[test] fn test_create_cred_def() { init!("true"); - let (id, _) = create_cred_def("did", SCHEMAS_JSON, "tag_1", None, Some(false)).unwrap(); + let (id, _) = create_cred_def("did", SCHEMAS_JSON, "tag_1", None, Some(false)).unwrap(); assert_eq!(id, CRED_DEF_ID); } @@ -783,7 +766,7 @@ pub mod tests { let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let rc = create_rev_reg_def(&did, &cred_def_id, get_temp_dir_path(Some("path.txt")).to_str().unwrap(), 2); - assert_eq!(rc, Err(LIBINDY_INVALID_STRUCTURE.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::LibindyInvalidStructure); } #[cfg(feature = "pool_tests")] @@ -842,7 +825,7 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] - fn from_pool_ledger_with_id(){ + fn from_pool_ledger_with_id() { use settings; init!("ledger"); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); @@ -852,11 +835,10 @@ pub mod tests { let (id, retrieved_schema) = rc.unwrap(); assert!(retrieved_schema.contains(&schema_id)); - } #[test] - fn from_ledger_schema_id(){ + fn from_ledger_schema_id() { init!("true"); let (id, retrieved_schema) = get_schema_json(SCHEMA_ID).unwrap(); assert_eq!(&retrieved_schema, SCHEMA_JSON); @@ -865,7 +847,7 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] - fn test_revoke_credential(){ + fn test_revoke_credential() { init!("ledger"); let (_, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) = ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, true); @@ -874,13 +856,13 @@ pub mod tests { let (_, first_rev_reg_delta, first_timestamp) = get_rev_reg_delta_json(&rev_reg_id, None, None).unwrap(); let (_, test_same_delta, test_same_timestamp) = get_rev_reg_delta_json(&rev_reg_id, None, None).unwrap(); - assert_eq!(first_rev_reg_delta, test_same_delta); + assert_eq!(first_rev_reg_delta, test_same_delta); assert_eq!(first_timestamp, test_same_timestamp); let (payment, revoked_rev_reg_delta) = revoke_credential(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap(), &rev_reg_id, cred_rev_id.unwrap().as_str()).unwrap(); // Delta should change after revocation - let (_, second_rev_reg_delta, _) = get_rev_reg_delta_json(&rev_reg_id, Some(first_timestamp+1), None).unwrap(); + let (_, second_rev_reg_delta, _) = get_rev_reg_delta_json(&rev_reg_id, Some(first_timestamp + 1), None).unwrap(); assert!(payment.is_some()); assert_ne!(first_rev_reg_delta, second_rev_reg_delta); diff --git a/vcx/libvcx/src/utils/libindy/cache.rs b/vcx/libvcx/src/utils/libindy/cache.rs index 077d3c43dc..ac20cf219a 100644 --- a/vcx/libvcx/src/utils/libindy/cache.rs +++ b/vcx/libvcx/src/utils/libindy/cache.rs @@ -1,4 +1,4 @@ -extern crate serde_json; +use serde_json; use utils::libindy::wallet::{add_record, get_record, update_record_value}; diff --git a/vcx/libvcx/src/utils/libindy/callback.rs b/vcx/libvcx/src/utils/libindy/callback.rs index 3cecbdb082..8d58c1851e 100644 --- a/vcx/libvcx/src/utils/libindy/callback.rs +++ b/vcx/libvcx/src/utils/libindy/callback.rs @@ -1,4 +1,4 @@ -extern crate libc; +extern crate libc; use self::libc::c_char; use std::ffi::CStr; diff --git a/vcx/libvcx/src/utils/libindy/callback_u32.rs b/vcx/libvcx/src/utils/libindy/callback_u32.rs index c50f16a1ea..a4c82e5c4b 100644 --- a/vcx/libvcx/src/utils/libindy/callback_u32.rs +++ b/vcx/libvcx/src/utils/libindy/callback_u32.rs @@ -1,6 +1,4 @@ -extern crate libc; - -use self::libc::c_char; +use libc::c_char; use std::collections::HashMap; use std::sync::Mutex; use std::ops::Deref; diff --git a/vcx/libvcx/src/utils/libindy/crypto.rs b/vcx/libvcx/src/utils/libindy/crypto.rs index 9a8a0eab65..0eb2c6618a 100644 --- a/vcx/libvcx/src/utils/libindy/crypto.rs +++ b/vcx/libvcx/src/utils/libindy/crypto.rs @@ -1,17 +1,16 @@ /* test isn't ready until > libindy 1.0.1 */ -extern crate libc; - use futures::Future; +use indy::crypto; use utils::libindy::mock_libindy_rc; use utils::libindy::error_codes::map_rust_indy_sdk_error; use settings; -use indy::crypto; +use error::prelude::*; -pub fn prep_msg(sender_vk: &str, recipient_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn prep_msg(sender_vk: &str, recipient_vk: &str, msg: &[u8]) -> VcxResult> { if settings::test_indy_mode_enabled() { let rc = mock_libindy_rc(); - if rc != 0 { return Err(rc); }; + if rc != 0 { return Err(VcxError::from(VcxErrorKind::Common(rc))); }; return Ok(Vec::from(msg).to_owned()); } @@ -20,7 +19,7 @@ pub fn prep_msg(sender_vk: &str, recipient_vk: &str, msg: &[u8]) -> Result Result, u32> { +pub fn prep_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> VcxResult> { if settings::test_indy_mode_enabled() { return Ok(Vec::from(msg).to_owned()); } crypto::anon_crypt(recipient_vk, msg) @@ -28,7 +27,7 @@ pub fn prep_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> Result, u32 .map_err(map_rust_indy_sdk_error) } -pub fn parse_msg(recipient_vk: &str, msg: &[u8]) -> Result<(String, Vec), u32> { +pub fn parse_msg(recipient_vk: &str, msg: &[u8]) -> VcxResult<(String, Vec)> { if settings::test_indy_mode_enabled() { return Ok((::utils::constants::VERKEY.to_string(), Vec::from(msg).to_owned())); } crypto::auth_decrypt(::utils::libindy::wallet::get_wallet_handle(), recipient_vk, msg) @@ -36,7 +35,7 @@ pub fn parse_msg(recipient_vk: &str, msg: &[u8]) -> Result<(String, Vec), u3 .map_err(map_rust_indy_sdk_error) } -pub fn parse_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn parse_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> VcxResult> { if settings::test_indy_mode_enabled() { return Ok(Vec::from(msg).to_owned()); } crypto::anon_decrypt(::utils::libindy::wallet::get_wallet_handle(), recipient_vk, msg) @@ -44,7 +43,7 @@ pub fn parse_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> Result, u3 .map_err(map_rust_indy_sdk_error) } -pub fn sign(my_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn sign(my_vk: &str, msg: &[u8]) -> VcxResult> { if settings::test_indy_mode_enabled() { return Ok(Vec::from(msg).to_owned()); } crypto::sign(::utils::libindy::wallet::get_wallet_handle(), my_vk, msg) @@ -52,21 +51,21 @@ pub fn sign(my_vk: &str, msg: &[u8]) -> Result, u32> { .map_err(map_rust_indy_sdk_error) } -pub fn verify(vk: &str, msg: &[u8], signature: &[u8]) -> Result { - if settings::test_indy_mode_enabled() { return Ok(true) } +pub fn verify(vk: &str, msg: &[u8], signature: &[u8]) -> VcxResult { + if settings::test_indy_mode_enabled() { return Ok(true); } crypto::verify(vk, msg, signature) - .wait() - .map_err(map_rust_indy_sdk_error) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn pack_message(sender_vk: Option<&str>, receiver_keys: &str, msg: &[u8]) -> Result, u32> { +pub fn pack_message(sender_vk: Option<&str>, receiver_keys: &str, msg: &[u8]) -> VcxResult> { crypto::pack_message(::utils::libindy::wallet::get_wallet_handle(), msg, receiver_keys, sender_vk) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn unpack_message(msg: &[u8]) -> Result, u32> { +pub fn unpack_message(msg: &[u8]) -> VcxResult> { crypto::unpack_message(::utils::libindy::wallet::get_wallet_handle(), msg) .wait() .map_err(map_rust_indy_sdk_error) diff --git a/vcx/libvcx/src/utils/libindy/error_codes.rs b/vcx/libvcx/src/utils/libindy/error_codes.rs index c37568b247..58dc3ef802 100644 --- a/vcx/libvcx/src/utils/libindy/error_codes.rs +++ b/vcx/libvcx/src/utils/libindy/error_codes.rs @@ -1,9 +1,10 @@ extern crate num_traits; +use self::num_traits::int::PrimInt; + use indy::IndyError; use utils::error; -use std::ffi::NulError; -use self::num_traits::int::PrimInt; +use error::prelude::{VcxError, VcxErrorKind}; pub fn map_indy_error(rtn: T, error_code: C) -> Result { if error_code == C::zero() { @@ -13,33 +14,23 @@ pub fn map_indy_error(rtn: T, error_code: C) -> Result { Err(map_indy_error_code(error_code)) } -// Todo - this will replace map_indy_error_code once we stop using our own indy cbs and move everything to rust-indy-sdk -// Todo - rename once it replaces map_indy_error -pub fn map_rust_indy_sdk_error(error_code: IndyError) -> u32 { - let error_code = error_code.error_code as u32; - if error_code >= error::UNKNOWN_ERROR.code_num { - return error_code; - } - - warn!("indy-sdk error code: {}", error_code); - - match error_code { - 100 ... 111 => error::INVALID_LIBINDY_PARAM.code_num, - 113 => error::LIBINDY_INVALID_STRUCTURE.code_num, - 114 => error::IOERROR.code_num, - 200 => error::INVALID_WALLET_HANDLE.code_num, - 203 => error::WALLET_ALREADY_EXISTS.code_num, - 204 => error::WALLET_NOT_FOUND.code_num, - 206 => error::WALLET_ALREADY_OPEN.code_num, - 212 => error::WALLET_RECORD_NOT_FOUND.code_num, - 213 => error::DUPLICATE_WALLET_RECORD.code_num, - 306 => error::CREATE_POOL_CONFIG.code_num, - 404 => error::DUPLICATE_MASTER_SECRET.code_num, - 407 => error::CREDENTIAL_DEF_ALREADY_CREATED.code_num, - 600 => error::DID_ALREADY_EXISTS_IN_WALLET.code_num, - 702 => error::INSUFFICIENT_TOKEN_AMOUNT.code_num, - - _ => error::UNKNOWN_LIBINDY_ERROR.code_num +pub fn map_rust_indy_sdk_error(error: IndyError) -> VcxError { + match error.error_code as u32 { + 100 ... 111 => VcxError::from_msg(VcxErrorKind::InvalidLibindyParam, error.message), + 113 => VcxError::from_msg(VcxErrorKind::LibindyInvalidStructure, error.message), + 114 => VcxError::from_msg(VcxErrorKind::IOError, error.message), + 200 => VcxError::from_msg(VcxErrorKind::InvalidWalletHandle, error.message), + 203 => VcxError::from_msg(VcxErrorKind::DuplicationWallet, error.message), + 204 => VcxError::from_msg(VcxErrorKind::WalletNotFound, error.message), + 206 => VcxError::from_msg(VcxErrorKind::WalletAlreadyOpen, error.message), + 212 => VcxError::from_msg(VcxErrorKind::WalletRecordNotFound, error.message), + 213 => VcxError::from_msg(VcxErrorKind::DuplicationWalletRecord, error.message), + 306 => VcxError::from_msg(VcxErrorKind::CreatePoolConfig, error.message), + 404 => VcxError::from_msg(VcxErrorKind::DuplicationMasterSecret, error.message), + 407 => VcxError::from_msg(VcxErrorKind::CredDefAlreadyCreated, error.message), + 600 => VcxError::from_msg(VcxErrorKind::DuplicationDid, error.message), + 702 => VcxError::from_msg(VcxErrorKind::InsufficientTokenAmount, error.message), + _ => VcxError::from_msg(VcxErrorKind::UnknownLiibndyError, error.message) } } @@ -73,11 +64,6 @@ pub fn map_indy_error_code(error_code: C) -> u32 { } } -pub fn map_string_error(err: NulError) -> u32 { - error!("Invalid String: {:?}", err); - error::UNKNOWN_LIBINDY_ERROR.code_num -} - #[cfg(test)] pub mod tests { use super::*; @@ -106,10 +92,10 @@ pub mod tests { indy_backtrace: None, }; - assert_eq!(map_rust_indy_sdk_error(err100), error::INVALID_LIBINDY_PARAM.code_num); - assert_eq!(map_rust_indy_sdk_error(err107), error::INVALID_LIBINDY_PARAM.code_num); - assert_eq!(map_rust_indy_sdk_error(err111), error::INVALID_LIBINDY_PARAM.code_num); + assert_eq!(map_rust_indy_sdk_error(err100).kind(), VcxErrorKind::InvalidLibindyParam); + assert_eq!(map_rust_indy_sdk_error(err107).kind(), VcxErrorKind::InvalidLibindyParam); + assert_eq!(map_rust_indy_sdk_error(err111).kind(), VcxErrorKind::InvalidLibindyParam); // Test that RC 112 falls out of the range 100...112 - assert_ne!(map_rust_indy_sdk_error(err112), error::INVALID_LIBINDY_PARAM.code_num); + assert_ne!(map_rust_indy_sdk_error(err112).kind(), VcxErrorKind::InvalidLibindyParam); } } diff --git a/vcx/libvcx/src/utils/libindy/ledger.rs b/vcx/libvcx/src/utils/libindy/ledger.rs index 3c8f7724f7..c98da66b87 100644 --- a/vcx/libvcx/src/utils/libindy/ledger.rs +++ b/vcx/libvcx/src/utils/libindy/ledger.rs @@ -1,33 +1,29 @@ -extern crate libc; -extern crate time; -extern crate serde_json; - +use serde_json; use futures::Future; +use indy::ledger; use settings; -use utils::libindy::{ - pool::get_pool_handle, - wallet::get_wallet_handle, -}; -use utils::error; -use indy::ledger; +use utils::libindy::pool::get_pool_handle; +use utils::libindy::wallet::get_wallet_handle; use utils::libindy::error_codes::map_rust_indy_sdk_error; +use error::prelude::*; -pub fn multisign_request(did: &str, request: &str) -> Result { - ledger::multi_sign_request(get_wallet_handle(), did, request) - .wait() - .map_err(map_rust_indy_sdk_error) +pub fn multisign_request(did: &str, request: &str) -> VcxResult { + ledger::multi_sign_request(get_wallet_handle(), did, request) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn libindy_sign_request(did: &str, request: &str) -> Result { +pub fn libindy_sign_request(did: &str, request: &str) -> VcxResult { ledger::sign_request(get_wallet_handle(), did, request) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_sign_and_submit_request(issuer_did: &str, request_json: &str) -> Result { +pub fn libindy_sign_and_submit_request(issuer_did: &str, request_json: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(r#"{"rc":"success"}"#.to_string()); } - let pool_handle = get_pool_handle().or(Err(error::NO_POOL_OPEN.code_num))?; + + let pool_handle = get_pool_handle()?; let wallet_handle = get_wallet_handle(); ledger::sign_and_submit_request(pool_handle, wallet_handle, issuer_did, request_json) @@ -35,45 +31,46 @@ pub fn libindy_sign_and_submit_request(issuer_did: &str, request_json: &str) -> .map_err(map_rust_indy_sdk_error) } -pub fn libindy_submit_request(request_json: &str) -> Result { - let pool_handle = get_pool_handle().or(Err(error::NO_POOL_OPEN.code_num))?; +pub fn libindy_submit_request(request_json: &str) -> VcxResult { + let pool_handle = get_pool_handle()?; + //TODO there was timeout here (before future-based Rust wrapper) ledger::submit_request(pool_handle, request_json) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_build_get_txn_request(submitter_did: &str, sequence_num: i32) -> Result { +pub fn libindy_build_get_txn_request(submitter_did: &str, sequence_num: i32) -> VcxResult { ledger::build_get_txn_request(Some(submitter_did), None, sequence_num) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_build_schema_request(submitter_did: &str, data: &str) -> Result { +pub fn libindy_build_schema_request(submitter_did: &str, data: &str) -> VcxResult { ledger::build_schema_request(submitter_did, data) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_build_get_schema_request(submitter_did: &str, schema_id: &str) -> Result { +pub fn libindy_build_get_schema_request(submitter_did: &str, schema_id: &str) -> VcxResult { ledger::build_get_schema_request(Some(submitter_did), schema_id) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_parse_get_schema_response(get_schema_response: &str) -> Result<(String, String), u32> { +pub fn libindy_parse_get_schema_response(get_schema_response: &str) -> VcxResult<(String, String)> { ledger::parse_get_schema_response(get_schema_response) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_parse_get_cred_def_response(get_cred_def_response: &str) -> Result<(String, String), u32> { +pub fn libindy_parse_get_cred_def_response(get_cred_def_response: &str) -> VcxResult<(String, String)> { ledger::parse_get_cred_def_response(get_cred_def_response) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn libindy_build_get_credential_def_txn(cred_def_id: &str) -> Result{ +pub fn libindy_build_get_credential_def_txn(cred_def_id: &str) -> VcxResult { let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; ledger::build_get_cred_def_request(Some(&submitter_did), cred_def_id) .wait() @@ -81,8 +78,52 @@ pub fn libindy_build_get_credential_def_txn(cred_def_id: &str) -> Result Result{ + credential_def_json: &str) -> VcxResult { ledger::build_cred_def_request(submitter_did, credential_def_json) .wait() .map_err(map_rust_indy_sdk_error) } + +pub fn parse_response(response: &str) -> VcxResult { + serde_json::from_str::(response) + .to_vcx(VcxErrorKind::InvalidJson, "Cannot deserialize transaction response") +} + +#[serde(tag = "op")] +#[derive(Deserialize, Debug)] +pub enum Response { + #[serde(rename = "REQNACK")] + ReqNACK(Reject), + #[serde(rename = "REJECT")] + Reject(Reject), + #[serde(rename = "REPLY")] + Reply(Reply), +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Reject { + pub reason: String +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum Reply { + ReplyV0(ReplyV0), + ReplyV1(ReplyV1) +} + +#[derive(Debug, Deserialize)] +pub struct ReplyV0 { + pub result: serde_json::Value +} + +#[derive(Debug, Deserialize)] +pub struct ReplyV1 { + pub data: ReplyDataV1 +} + +#[derive(Debug, Deserialize)] +pub struct ReplyDataV1 { + pub result: serde_json::Value +} diff --git a/vcx/libvcx/src/utils/libindy/logger.rs b/vcx/libvcx/src/utils/libindy/logger.rs index 9c33ec2edb..b6db1f6865 100644 --- a/vcx/libvcx/src/utils/libindy/logger.rs +++ b/vcx/libvcx/src/utils/libindy/logger.rs @@ -2,13 +2,14 @@ extern crate log; use indy::logger; use utils::libindy::error_codes::map_rust_indy_sdk_error; +use error::prelude::*; -pub fn set_logger(logger: &'static log::Log) -> Result<(), u32> { +pub fn set_logger(logger: &'static log::Log) -> VcxResult<()> { logger::set_logger(logger) .map_err(map_rust_indy_sdk_error) } -pub fn set_default_logger(patter: Option<&str>) -> Result<(), u32> { +pub fn set_default_logger(patter: Option<&str>) -> VcxResult<()> { logger::set_default_logger(patter) .map_err(map_rust_indy_sdk_error) } \ No newline at end of file diff --git a/vcx/libvcx/src/utils/libindy/mod.rs b/vcx/libvcx/src/utils/libindy/mod.rs index c4c869bf5a..10f29cd8fe 100644 --- a/vcx/libvcx/src/utils/libindy/mod.rs +++ b/vcx/libvcx/src/utils/libindy/mod.rs @@ -12,11 +12,10 @@ pub mod logger; pub mod error_codes; -extern crate libc; - use settings; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use std::sync::Mutex; +use error::prelude::*; lazy_static!{ static ref NEXT_LIBINDY_RC: Mutex> = Mutex::new(vec![]); @@ -36,7 +35,7 @@ pub fn next_u32_command_handle() -> u32 { (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as u32 } -pub fn init_pool() -> Result<(), u32> { +pub fn init_pool() -> VcxResult<()> { trace!("init_pool >>>"); if settings::test_indy_mode_enabled() {return Ok (()); } diff --git a/vcx/libvcx/src/utils/libindy/payments.rs b/vcx/libvcx/src/utils/libindy/payments.rs index 1ff5264fcc..2c4e906d68 100644 --- a/vcx/libvcx/src/utils/libindy/payments.rs +++ b/vcx/libvcx/src/utils/libindy/payments.rs @@ -1,22 +1,16 @@ -extern crate libc; -extern crate serde_json; - use futures::Future; - -use utils::libindy::wallet::get_wallet_handle; -use utils::constants::{SUBMIT_SCHEMA_RESPONSE, TRANSFER_TXN_TYPE}; -use utils::libindy::error_codes::map_rust_indy_sdk_error; -#[allow(unused_imports)] -use utils::libindy::ledger::{libindy_submit_request, libindy_sign_and_submit_request, libindy_sign_request}; -use utils::error; -use error::payment::PaymentError; -use error::ToErrorCode; - use indy::payments; +use serde_json::Value; + use std::fmt; use std::collections::HashMap; -use serde_json::Value; + +use utils::libindy::wallet::get_wallet_handle; +use utils::libindy::ledger::{libindy_submit_request, libindy_sign_and_submit_request, libindy_sign_request}; +use utils::libindy::error_codes::{map_rust_indy_sdk_error}; +use utils::constants::{SUBMIT_SCHEMA_RESPONSE, TRANSFER_TXN_TYPE}; use settings; +use error::prelude::*; static DEFAULT_FEES: &str = r#"{"0":0, "1":0, "101":2, "10001":0, "102":42, "103":0, "104":0, "105":0, "107":0, "108":0, "109":0, "110":0, "111":0, "112":0, "113":2, "114":2, "115":0, "116":0, "117":0, "118":0, "119":0}"#; @@ -59,7 +53,7 @@ pub struct Output { impl fmt::Display for WalletInfo { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match serde_json::to_string(&self) { + match ::serde_json::to_string(&self) { Ok(s) => write!(f, "{}", s), Err(e) => write!(f, "null"), } @@ -75,17 +69,13 @@ pub struct PaymentTxn { } impl PaymentTxn { - pub fn from_parts(inputs: &str, outputs: &str, amount: u64, credit: bool) -> Result { - let inputs: Vec = serde_json::from_str(&inputs) - .map_err(|err| { error::INVALID_JSON.code_num })?; - let outputs: Vec = serde_json::from_str(&outputs) - .map_err(|err| { error::INVALID_JSON.code_num })?; - Ok(PaymentTxn { + pub fn from_parts(inputs: Vec, outputs: Vec, amount: u64, credit: bool) -> PaymentTxn { + PaymentTxn { amount, credit, inputs, outputs, - }) + } } } @@ -93,7 +83,7 @@ pub fn build_test_address(address: &str) -> String { format!("pay:{}:{}", ::settings::get_payment_method(), address) } -pub fn create_address(seed: Option) -> Result { +pub fn create_address(seed: Option) -> VcxResult { trace!("create_address >>> seed: {:?}", seed); if settings::test_indy_mode_enabled() { @@ -101,8 +91,8 @@ pub fn create_address(seed: Option) -> Result { } let config = match seed { - Some(x) => format!("{{\"seed\":\"{}\"}}", x), - None => format!("{{}}"), + Some(x) => json!({"seed": x}).to_string(), + None => "{}".to_string(), }; payments::create_payment_address(get_wallet_handle() as i32, settings::get_payment_method().as_str(), &config) @@ -110,7 +100,7 @@ pub fn create_address(seed: Option) -> Result { .map_err(map_rust_indy_sdk_error) } -pub fn get_address_info(address: &str) -> Result { +pub fn get_address_info(address: &str) -> VcxResult { if settings::test_indy_mode_enabled() { let utxos = json!( [ @@ -129,7 +119,7 @@ pub fn get_address_info(address: &str) -> Result { ] ); - let utxo: Vec = serde_json::from_value(utxos).unwrap(); + let utxo: Vec = ::serde_json::from_value(utxos).unwrap(); return Ok(AddressInfo { address: address.to_string(), balance: _address_balance(&utxo), utxo }); } @@ -146,43 +136,44 @@ pub fn get_address_info(address: &str) -> Result { .wait() .map_err(map_rust_indy_sdk_error)?; - trace!("indy_parse_get_utxo_response() --> {}", response); - let utxo: Vec = serde_json::from_str(&response).or(Err(error::INVALID_JSON.code_num))?; + let utxo: Vec = ::serde_json::from_str(&response) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize payment sources response: {}", err)))?; - Ok(AddressInfo { address: address.to_string(), balance: _address_balance(&utxo), utxo }) + let info = AddressInfo { address: address.to_string(), balance: _address_balance(&utxo), utxo }; + + Ok(info) } -pub fn list_addresses() -> Result, u32> { +pub fn list_addresses() -> VcxResult> { if settings::test_indy_mode_enabled() { let addresses = json!([ build_test_address("9UFgyjuJxi1i1HD"), build_test_address("zR3GN9lfbCVtHjp") ]); - return Ok(serde_json::from_value(addresses).unwrap()); + return Ok(::serde_json::from_value(addresses).unwrap()); } let addresses = payments::list_payment_addresses(get_wallet_handle() as i32) .wait() .map_err(map_rust_indy_sdk_error)?; - trace!("--> {}", addresses); - Ok(serde_json::from_str(&addresses).or(Err(error::INVALID_JSON.code_num))?) + ::serde_json::from_str(&addresses) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize a list of payment addresses: {}", err))) } fn is_valid_address(address: &str, method: &str) -> bool { let prefix = format!("pay:{}", method); - address.starts_with(&prefix) } -pub fn get_wallet_token_info() -> Result { +pub fn get_wallet_token_info() -> VcxResult { trace!("get_wallet_token_info >>>"); let addresses = list_addresses()?; - let method = settings::get_config_value(settings::CONFIG_PAYMENT_METHOD)?; - let mut balance = 0; + let mut wallet_info = Vec::new(); + let mut balance = 0; for address in addresses.iter() { if is_valid_address(&address, &method) { @@ -204,123 +195,121 @@ pub fn get_wallet_token_info() -> Result { Ok(info) } -pub fn get_ledger_fees() -> Result { +pub fn get_ledger_fees() -> VcxResult { trace!("get_ledger_fees >>>"); if settings::test_indy_mode_enabled() { return Ok(DEFAULT_FEES.to_string()); } - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(error::INVALID_CONFIGURATION.code_num))?; + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; - let response = match payments::build_get_txn_fees_req(get_wallet_handle() as i32, Some(&did), settings::get_payment_method().as_str()).wait() { - Ok(txn) => libindy_sign_and_submit_request(&did, &txn)?, - Err(x) => return Err(map_rust_indy_sdk_error(x)), - }; + let txn = payments::build_get_txn_fees_req(get_wallet_handle(), Some(&did), settings::get_payment_method().as_str()) + .wait() + .map_err(map_rust_indy_sdk_error)?; + + let response = libindy_sign_and_submit_request(&did, &txn)?; - let res = payments::parse_get_txn_fees_response(settings::get_payment_method().as_str(), &response) + payments::parse_get_txn_fees_response(settings::get_payment_method().as_str(), &response) .wait() - .map_err(map_rust_indy_sdk_error); - res + .map_err(map_rust_indy_sdk_error) } -pub fn pay_for_txn(req: &str, txn_type: &str) -> Result<(Option, String), u32> { +pub fn pay_for_txn(req: &str, txn_type: &str) -> VcxResult<(Option, String)> { debug!("pay_for_txn(req: {}, txn_type: {})", req, txn_type); if settings::test_indy_mode_enabled() { - let inputs = format!(r#"["{}"]"#, build_test_address("9UFgyjuJxi1i1HD")); - - let outputs = format!(r#"[ - {{ - "amount": 1, - "extra": null, - "recipient": "{}" - }} - ]"#, build_test_address("xkIsxem0YNtHrRO")); - - return Ok((Some(PaymentTxn::from_parts(&inputs, &outputs, 1, false).unwrap()), SUBMIT_SCHEMA_RESPONSE.to_string())); + let inputs = vec!["pay:null:9UFgyjuJxi1i1HD".to_string()]; + let outputs = serde_json::from_str::>(r#"[{"amount":1,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#).unwrap(); + return Ok((Some(PaymentTxn::from_parts(inputs, outputs, 1, false)), SUBMIT_SCHEMA_RESPONSE.to_string())); } let txn_price = get_txn_price(txn_type)?; if txn_price == 0 { - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(error::INVALID_CONFIGURATION.code_num))?; + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; let txn_response = libindy_sign_and_submit_request(&did, req)?; Ok((None, txn_response)) } else { - let (refund, inputs, refund_address) = inputs(txn_price).map_err(|e| e.to_error_code())?; - - let output = outputs(refund, &refund_address, None, None).map_err(|e| e.to_error_code())?; + let (refund, inputs, refund_address) = inputs(txn_price)?; + let output = outputs(refund, &refund_address, None, None)?; let (fee_response, txn_response) = _submit_fees_request(req, &inputs, &output)?; - let payment = PaymentTxn::from_parts(&inputs, &output, txn_price, false)?; + let payment = PaymentTxn::from_parts(inputs, output, txn_price, false); Ok((Some(payment), txn_response)) } } -fn _submit_fees_request(req: &str, inputs: &str, outputs: &str) -> Result<(String, String), u32> { - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(error::INVALID_CONFIGURATION.code_num))?; +fn _serialize_inputs_and_outputs(inputs: &Vec, outputs: &Vec) -> VcxResult<(String, String)> { + let inputs = ::serde_json::to_string(inputs) + .to_vcx(VcxErrorKind::InvalidJson, "Cannot serialize inputs")?; + let outputs = ::serde_json::to_string(outputs) + .to_vcx(VcxErrorKind::InvalidJson, "Cannot serialize outputs")?; + Ok((inputs, outputs)) +} + +fn _submit_fees_request(req: &str, inputs: &Vec, outputs: &Vec) -> VcxResult<(String, String)> { + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + + let (inputs, outputs) = _serialize_inputs_and_outputs(inputs, outputs)?; let req = libindy_sign_request(&did, req)?; - let (response, payment_method) = match payments::add_request_fees(get_wallet_handle(), - Some(&did), - &req, - &inputs, - &outputs, - None).wait() { - Ok((req, payment_method)) => { - (libindy_submit_request(&req)?, payment_method) - } - Err(x) => return Err(map_rust_indy_sdk_error(x)), - }; + let (req, payment_method) = + payments::add_request_fees(get_wallet_handle(), + Some(&did), + &req, + &inputs, + &outputs, + None) + .wait() + .map_err(map_rust_indy_sdk_error)?; - let parsed_response = match payments::parse_response_with_fees(&payment_method, &response).wait() { - Ok(x) => x, - Err(x) => return Err(error::INVALID_LEDGER_RESPONSE.code_num), - }; + let response = libindy_submit_request(&req)?; + + let parsed_response = payments::parse_response_with_fees(&payment_method, &response) + .wait() + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidLedgerResponse, format!("Cannot parse response: {}", err)))?; Ok((parsed_response, response)) } -pub fn pay_a_payee(price: u64, address: &str) -> Result<(PaymentTxn, String), PaymentError> { +pub fn pay_a_payee(price: u64, address: &str) -> VcxResult<(PaymentTxn, String)> { trace!("pay_a_payee >>> price: {}, address {}", price, address); debug!("sending {} tokens to address {}", price, address); - let ledger_cost = get_txn_price(TRANSFER_TXN_TYPE).map_err(|e| PaymentError::CommonError(e))?; + let ledger_cost = get_txn_price(TRANSFER_TXN_TYPE)?; let (remainder, input, refund_address) = inputs(price + ledger_cost)?; - let output = outputs(remainder, &refund_address, Some(address.to_string()), Some(price))?; + let outputs = outputs(remainder, &refund_address, Some(address.to_string()), Some(price))?; - let payment = PaymentTxn::from_parts(&input, &output, price, false).map_err(|e| PaymentError::CommonError(e))?; - let my_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(PaymentError::CommonError(error::INVALID_CONFIGURATION.code_num)))?; + let my_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; if settings::test_indy_mode_enabled() { - let inputs = format!(r#"["{}"]"#, build_test_address("9UFgyjuJxi1i1HD")); + let inputs = vec![build_test_address("9UFgyjuJxi1i1HD")]; - let outputs = format!(r#"[ - {{ - "amount": 1, - "extra": null, - "recipient": "{}" - }} - ]"#, build_test_address("xkIsxem0YNtHrRO")); - - return Ok((PaymentTxn::from_parts(&inputs, &outputs, 1, false).unwrap(), SUBMIT_SCHEMA_RESPONSE.to_string())); + let outputs = vec![Output { + source: None, + recipient: build_test_address("xkIsxem0YNtHrRO"), + amount: 1, + extra: None, + }]; + return Ok((PaymentTxn::from_parts(inputs, outputs, 1, false), SUBMIT_SCHEMA_RESPONSE.to_string())); } - match payments::build_payment_req(get_wallet_handle(), Some(&my_did), &input, &output, None).wait() { - Ok((request, payment_method)) => { - let result = libindy_submit_request(&request).map_err(|ec| PaymentError::CommonError(ec))?; - Ok((payment, result)) - } - Err(ec) => { - error!("error: {:?}", ec.message); - Err(PaymentError::CommonError(ec.error_code as u32)) - } - } + let (inputs_json, outputs_json) = _serialize_inputs_and_outputs(&input, &outputs)?; + + let (request, payment_method) = + payments::build_payment_req(get_wallet_handle(), Some(&my_did), &inputs_json, &outputs_json, None) + .wait() + .map_err(map_rust_indy_sdk_error)?; + + let result = libindy_submit_request(&request)?; + let payment = PaymentTxn::from_parts(input, outputs, price, false); + Ok((payment, result)) } -fn get_txn_price(txn_type: &str) -> Result { +fn get_txn_price(txn_type: &str) -> VcxResult { let ledger_fees = get_ledger_fees()?; - let fees: HashMap = serde_json::from_str(&ledger_fees).or(Err(error::INVALID_JSON.code_num))?; + let fees: HashMap = serde_json::from_str(&ledger_fees) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize fees: {}", err)))?; match fees.get(txn_type) { Some(x) => Ok(*x), @@ -332,15 +321,16 @@ fn _address_balance(address: &Vec) -> u64 { address.iter().fold(0, |balance, utxo| balance + utxo.amount) } -pub fn inputs(cost: u64) -> Result<(u64, String, String), PaymentError> { +pub fn inputs(cost: u64) -> VcxResult<(u64, Vec, String)> { let mut inputs: Vec = Vec::new(); let mut balance = 0; - let wallet_info: WalletInfo = get_wallet_token_info().map_err(|ec| PaymentError::CommonError(ec))?; let mut refund_address = String::new(); + let wallet_info: WalletInfo = get_wallet_token_info()?; + if wallet_info.balance < cost { warn!("not enough tokens in wallet to pay: balance: {}, cost: {}", wallet_info.balance, cost); - return Err(PaymentError::InsufficientFunds()); + return Err(VcxError::from_msg(VcxErrorKind::InsufficientTokenAmount, format!("Not enough tokens in wallet to pay: balance: {}, cost: {}", wallet_info.balance, cost))); } // Todo: explore 'smarter' ways of selecting utxos ie bitcoin algorithms etc @@ -348,39 +338,35 @@ pub fn inputs(cost: u64) -> Result<(u64, String, String), PaymentError> { refund_address = address.address.clone(); 'inner: for utxo in address.utxo.iter() { if balance < cost { - inputs.push(utxo.source.clone().ok_or(PaymentError::InsufficientFunds())?.to_string()); + inputs.push(utxo.source.clone().ok_or(VcxErrorKind::InsufficientTokenAmount)?.to_string()); balance += utxo.amount; } else { break 'outer } } } let remainder = balance - cost; - let inputs = serde_json::to_string(&inputs).or(Err(PaymentError::InvalidWalletJson()))?; Ok((remainder, inputs, refund_address)) } -pub fn outputs(remainder: u64, refund_address: &str, payee_address: Option, payee_amount: Option) -> Result { +pub fn outputs(remainder: u64, refund_address: &str, payee_address: Option, payee_amount: Option) -> VcxResult> { // In the future we might provide a way for users to specify multiple output address for their remainder tokens // As of now, we only handle one output address which we create let mut outputs = Vec::new(); if remainder > 0 { - outputs.push(json!({ "recipient": refund_address, "amount": remainder })); + outputs.push(Output { source: None, recipient: refund_address.to_string(), amount: remainder, extra: None }); } if let Some(address) = payee_address { - outputs.push(json!({ - "recipient": address, - "amount": payee_amount, - })); + outputs.push(Output { source: None, recipient: address, amount: payee_amount.unwrap_or(0), extra: None }); } - Ok(serde_json::to_string(&outputs).or(Err(PaymentError::InvalidWalletJson()))?) + Ok(outputs) } // This is used for testing purposes only!!! -pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_address: Option, fees: Option, seed: Option) -> Result<(), u32> { +pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_address: Option, fees: Option, seed: Option) -> VcxResult<()> { trace!("mint_tokens_and_set_fees >>> number_of_addresses: {:?}, tokens_per_address: {:?}, fees: {:?}, seed: {:?}", number_of_addresses, tokens_per_address, fees, seed); @@ -392,9 +378,9 @@ pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_add None }; - let (did_2, _) = add_new_trustee_did()?; - let (did_3, _) = add_new_trustee_did()?; - let (did_4, _) = add_new_trustee_did()?; + let (did_2, _) = add_new_trustee_did(); + let (did_3, _) = add_new_trustee_did(); + let (did_4, _) = add_new_trustee_did(); let number_of_addresses = number_of_addresses.unwrap_or(1); @@ -439,17 +425,15 @@ pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_add Ok(()) } -fn add_new_trustee_did() -> Result<(String, String), u32> { +fn add_new_trustee_did() -> (String, String) { use indy::ledger; let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (did, verkey) = ::utils::libindy::signus::create_and_store_my_did(None).unwrap(); - let req_nym = ledger::build_nym_request(&institution_did, &did, Some(&verkey), None, Some("TRUSTEE")) - .wait() - .map_err(map_rust_indy_sdk_error)?; - ::utils::libindy::ledger::libindy_sign_and_submit_request(&institution_did, &req_nym)?; - Ok((did, verkey)) + let req_nym = ledger::build_nym_request(&institution_did, &did, Some(&verkey), None, Some("TRUSTEE")).wait().unwrap(); + ::utils::libindy::ledger::libindy_sign_and_submit_request(&institution_did, &req_nym).unwrap(); + (did, verkey) } #[cfg(test)] @@ -575,19 +559,19 @@ pub mod tests { let pay_addr_2 = build_test_address("2"); // Success - Exact amount - let expected_inputs = format!(r#"["{}","{}","{}","{}"]"#, pay_addr_1, pay_addr_2, pay_addr_1, pay_addr_2); + let expected_inputs = vec![pay_addr_1.clone(), pay_addr_2.clone(), pay_addr_1.clone(), pay_addr_2.clone()]; assert_eq!(inputs(6).unwrap(), (0, expected_inputs, build_test_address("zR3GN9lfbCVtHjp"))); // Success - utxo with remainder tokens - let expected_inputs = format!(r#"["{}","{}","{}","{}"]"#, pay_addr_1, pay_addr_2, pay_addr_1, pay_addr_2); + let expected_inputs = vec![pay_addr_1.clone(), pay_addr_2.clone(), pay_addr_1.clone(), pay_addr_2.clone()]; assert_eq!(inputs(5).unwrap(), (1, expected_inputs, build_test_address("zR3GN9lfbCVtHjp"))); // Success - requesting amount that partial address (1 of 2 utxos) can satisfy - let expected_inputs = format!(r#"["{}"]"#, pay_addr_1); + let expected_inputs = vec![pay_addr_1.clone()]; assert_eq!(inputs(1).unwrap(), (0, expected_inputs, build_test_address("9UFgyjuJxi1i1HD"))); // Err - request more than wallet contains - assert_eq!(inputs(7).err(), Some(PaymentError::InsufficientFunds())); + assert_eq!(inputs(7).err().unwrap().kind(), VcxErrorKind::InsufficientTokenAmount); } #[test] @@ -596,12 +580,12 @@ pub mod tests { let mut cost = 5; let (remainder, _, refund_address) = inputs(cost).unwrap(); - let mut expected_output = format!(r#"[{{"amount":1,"recipient":"{}"}}]"#, refund_address); + let mut expected_output: Vec = ::serde_json::from_str(&format!(r#"[{{"amount":1,"recipient":"{}"}}]"#, refund_address)).unwrap(); assert_eq!(outputs(remainder, &refund_address, None, None).unwrap(), expected_output); // No remainder so don't create an address in outputs cost = 6; - expected_output = r#"[]"#.to_string(); + expected_output = vec![]; let (remainder, _, refund_address) = inputs(cost).unwrap(); assert_eq!(remainder, 0); assert_eq!(outputs(remainder, &refund_address, None, None).unwrap(), expected_output); @@ -614,7 +598,7 @@ pub mod tests { let payee_amount = 11; let payee_address = build_test_address("payee_address"); let refund_address = build_test_address("refund_address"); - let expected_output = format!(r#"[{{"amount":4,"recipient":"{}"}},{{"amount":11,"recipient":"{}"}}]"#, refund_address, payee_address); + let expected_output: Vec = ::serde_json::from_str(&format!(r#"[{{"amount":4,"recipient":"{}"}},{{"amount":11,"recipient":"{}"}}]"#, refund_address, payee_address)).unwrap(); assert_eq!(outputs(4, refund_address.as_str(), Some(payee_address), Some(payee_amount)).unwrap(), expected_output); } @@ -690,7 +674,7 @@ pub mod tests { let price = get_my_balance() + 5; let result_from_paying = pay_a_payee(price, payment_address); - assert_eq!(result_from_paying.err(), Some(PaymentError::InsufficientFunds())); + assert_eq!(result_from_paying.err().unwrap().kind(), VcxErrorKind::InsufficientTokenAmount); assert_eq!(get_my_balance(), 5); } @@ -705,7 +689,7 @@ pub mod tests { let result_from_paying = pay_a_payee(0, payment_address); assert!(result_from_paying.is_err()); - assert_eq!(result_from_paying.err(), Some(PaymentError::CommonError(error::UNKNOWN_LIBINDY_ERROR.code_num))); + assert_eq!(result_from_paying.err().unwrap().kind(), VcxErrorKind::LiibndyError(100)); // TODO: FIXME } #[cfg(feature = "pool_tests")] @@ -735,7 +719,7 @@ pub mod tests { let price = get_my_balance() - not_enough_for_ledger_fee; assert!(price > 0); let result_from_paying = pay_a_payee(price, payment_address); - assert_eq!(result_from_paying.err(), Some(PaymentError::CommonError(error::INSUFFICIENT_TOKEN_AMOUNT.code_num))); + assert_eq!(result_from_paying.err().unwrap().kind(), VcxErrorKind::InsufficientTokenAmount); } #[cfg(feature = "pool_tests")] @@ -771,7 +755,7 @@ pub mod tests { assert_eq!(remainder, remaining_balance); let output = outputs(remainder, &refund_address, None, None).unwrap(); - assert_eq!(output, format!(r#"[{{"amount":{},"recipient":"{}"}}]"#, remaining_balance, refund_address)); + let expected_output: Vec = ::serde_json::from_str(&format!(r#"[{{"amount":{},"recipient":"{}"}}]"#, remaining_balance, refund_address)).unwrap(); let rc = _submit_fees_request(&req, &inputs, &output).unwrap(); let end_wallet = get_wallet_token_info().unwrap(); diff --git a/vcx/libvcx/src/utils/libindy/pool.rs b/vcx/libvcx/src/utils/libindy/pool.rs index 7c52f8ebc8..20d3506c94 100644 --- a/vcx/libvcx/src/utils/libindy/pool.rs +++ b/vcx/libvcx/src/utils/libindy/pool.rs @@ -1,77 +1,79 @@ -extern crate libc; - use futures::Future; +use indy::{pool, ErrorCode}; -use utils::error; use std::sync::RwLock; + use settings; -use indy::pool; -use indy::ErrorCode; use utils::libindy::error_codes::map_rust_indy_sdk_error; +use error::prelude::*; lazy_static! { static ref POOL_HANDLE: RwLock> = RwLock::new(None); } -pub fn change_pool_handle(handle: Option){ +pub fn change_pool_handle(handle: Option) { let mut h = POOL_HANDLE.write().unwrap(); *h = handle; } -pub fn set_protocol_version() -> u32 { - match pool::set_protocol_version(settings::get_protocol_version()).wait() { - Ok(_) => error::SUCCESS.code_num, - Err(_) => error::UNKNOWN_LIBINDY_ERROR.code_num, - } +pub fn set_protocol_version() -> VcxResult<()> { + pool::set_protocol_version(settings::get_protocol_version()) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn create_pool_ledger_config(pool_name: &str, path: &str) -> Result<(), u32> { - let pool_config = format!(r#"{{"genesis_txn":"{}"}}"#, path); +pub fn create_pool_ledger_config(pool_name: &str, path: &str) -> VcxResult<()> { + let pool_config = json!({"genesis_txn": path}).to_string(); - match pool::create_pool_ledger_config(pool_name, Some(&pool_config)).wait() { - Ok(_) => Ok(()), + match pool::create_pool_ledger_config(pool_name, Some(&pool_config)) + .wait() { + Ok(x) => Ok(()), Err(x) => if x.error_code != ErrorCode::PoolLedgerConfigAlreadyExistsError { - Err(error::UNKNOWN_LIBINDY_ERROR.code_num) + Err(VcxError::from_msg(VcxErrorKind::UnknownLiibndyError, x)) } else { Ok(()) } } } -pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> Result { +pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> VcxResult { + set_protocol_version()?; - set_protocol_version(); + let handle = pool::open_pool_ledger(pool_name, config) + .wait() + .map_err(map_rust_indy_sdk_error)?; - //TODO there was timeout here (before future-based Rust wrapper) - match pool::open_pool_ledger(pool_name, config).wait().map_err(map_rust_indy_sdk_error) { - Ok(x) => { - change_pool_handle(Some(x)); - Ok(x as u32) - }, - Err(_) => Err(error::UNKNOWN_LIBINDY_ERROR.code_num), - } + change_pool_handle(Some(handle)); + Ok(handle as u32) } -pub fn close() -> Result<(), u32> { +pub fn close() -> VcxResult<()> { let handle = get_pool_handle()?; change_pool_handle(None); + //TODO there was timeout here (before future-based Rust wrapper) - pool::close_pool_ledger(handle).wait().map_err(map_rust_indy_sdk_error) + pool::close_pool_ledger(handle) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn delete(pool_name: &str) -> Result<(), u32> { +pub fn delete(pool_name: &str) -> VcxResult<()> { trace!("delete >>> pool_name: {}", pool_name); if settings::test_indy_mode_enabled() { change_pool_handle(None); - return Ok(()) + return Ok(()); } - pool::delete_pool_ledger(pool_name).wait().map_err(map_rust_indy_sdk_error) + pool::delete_pool_ledger(pool_name) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn get_pool_handle() -> Result { - Ok(POOL_HANDLE.read().or(Err(error::NO_POOL_OPEN.code_num))?.ok_or(error::NO_POOL_OPEN.code_num)?) +pub fn get_pool_handle() -> VcxResult { + POOL_HANDLE.read() + .or(Err(VcxError::from_msg(VcxErrorKind::NoPoolOpen, "There is no pool opened")))? + .ok_or(VcxError::from_msg(VcxErrorKind::NoPoolOpen, "There is no pool opened")) } #[cfg(test)] diff --git a/vcx/libvcx/src/utils/libindy/signus.rs b/vcx/libvcx/src/utils/libindy/signus.rs index 5469030d0f..9b7b7409b7 100644 --- a/vcx/libvcx/src/utils/libindy/signus.rs +++ b/vcx/libvcx/src/utils/libindy/signus.rs @@ -1,28 +1,29 @@ -extern crate libc; - use futures::Future; +use indy::did; use settings; use utils::libindy::error_codes::map_rust_indy_sdk_error; -use indy::did; +use utils::libindy::wallet::get_wallet_handle; +use error::prelude::*; -pub fn create_and_store_my_did(seed: Option<&str>) -> Result<(String, String), u32> { +pub fn create_and_store_my_did(seed: Option<&str>) -> VcxResult<(String, String)> { if settings::test_indy_mode_enabled() { return Ok((::utils::constants::DID.to_string(), ::utils::constants::VERKEY.to_string())); } - let my_did_json = seed.map_or("{}".to_string(), |seed| format!("{{\"seed\":\"{}\" }}", seed)); - did::create_and_store_my_did(::utils::libindy::wallet::get_wallet_handle(), &my_did_json) + let my_did_json = seed.map_or(json!({}), |seed| json!({"seed": seed})); + + did::create_and_store_my_did(get_wallet_handle(), &my_did_json.to_string()) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn get_local_verkey(did: &str) -> Result { +pub fn get_local_verkey(did: &str) -> VcxResult { if settings::test_indy_mode_enabled() { return Ok(::utils::constants::VERKEY.to_string()); } - did::key_for_local_did(::utils::libindy::wallet::get_wallet_handle(), did) + did::key_for_local_did(get_wallet_handle(), did) .wait() .map_err(map_rust_indy_sdk_error) } diff --git a/vcx/libvcx/src/utils/libindy/wallet.rs b/vcx/libvcx/src/utils/libindy/wallet.rs index f07aaba807..da578046c2 100644 --- a/vcx/libvcx/src/utils/libindy/wallet.rs +++ b/vcx/libvcx/src/utils/libindy/wallet.rs @@ -1,31 +1,34 @@ -extern crate libc; -extern crate serde_json; - use futures::Future; +use indy::{wallet, ErrorCode}; use settings; use utils::libindy::error_codes::map_rust_indy_sdk_error; -use utils::error; -use error::wallet::WalletError; -use indy::wallet; -use indy::ErrorCode; + use std::path::Path; +use error::prelude::*; + pub static mut WALLET_HANDLE: i32 = 0; +pub fn set_wallet_handle(handle: i32) -> i32 { + unsafe { WALLET_HANDLE = handle; } + unsafe { WALLET_HANDLE } +} + pub fn get_wallet_handle() -> i32 { unsafe { WALLET_HANDLE } } -pub fn create_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> Result<(), u32> { +pub fn create_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> VcxResult<()> { trace!("creating wallet: {}", wallet_name); let config = settings::get_wallet_config(wallet_name, wallet_type, storage_config); let credentials = settings::get_wallet_credentials(storage_creds); - match wallet::create_wallet(&config, &credentials).wait() { + match wallet::create_wallet(&config, &credentials) + .wait() { Ok(x) => Ok(()), - Err(x) => if x.error_code != ErrorCode::WalletAlreadyExistsError && x.error_code != ErrorCode::Success { + Err(x) => if x.error_code != ErrorCode::WalletAlreadyExistsError { warn!("could not create wallet {}: {:?}", wallet_name, x.message); - Err(error::INVALID_WALLET_CREATION.code_num) + Err(VcxError::from_msg(VcxErrorKind::WalletCreate, format!("could not create wallet {}: {:?}", wallet_name, x.message))) } else { warn!("could not create wallet {}: {:?}", wallet_name, x.message); Ok(()) @@ -33,11 +36,10 @@ pub fn create_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_confi } } -pub fn open_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> Result { +pub fn open_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> VcxResult { trace!("open_wallet >>> wallet_name: {}", wallet_name); if settings::test_indy_mode_enabled() { - unsafe {WALLET_HANDLE = 1;} - return Ok(1); + return Ok(set_wallet_handle(1)); } let config = settings::get_wallet_config(wallet_name, wallet_type, storage_config); @@ -48,54 +50,55 @@ pub fn open_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: .wait() .map_err(map_rust_indy_sdk_error)?; - unsafe { WALLET_HANDLE = handle; } + set_wallet_handle(handle); Ok(handle) } -pub fn init_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> Result { +pub fn init_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> VcxResult { if settings::test_indy_mode_enabled() { - unsafe {WALLET_HANDLE = 1;} - return Ok(1); + return Ok(set_wallet_handle(1)); } create_wallet(wallet_name, wallet_type, storage_config, storage_creds)?; open_wallet(wallet_name, wallet_type, storage_config, storage_creds) } -pub fn close_wallet() -> Result<(), u32> { +pub fn close_wallet() -> VcxResult<()> { trace!("close_wallet >>>"); if settings::test_indy_mode_enabled() { - unsafe { WALLET_HANDLE = 0; } + set_wallet_handle(0); return Ok(()); } - let result = wallet::close_wallet(get_wallet_handle()).wait().map_err(map_rust_indy_sdk_error); - unsafe { WALLET_HANDLE = 0; } + let result = wallet::close_wallet(get_wallet_handle()) + .wait() + .map_err(map_rust_indy_sdk_error); + + set_wallet_handle(0); result } -pub fn delete_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> Result<(), u32> { +pub fn delete_wallet(wallet_name: &str, wallet_type: Option<&str>, storage_config: Option<&str>, storage_creds: Option<&str>) -> VcxResult<()> { trace!("delete_wallet >>> wallet_name: {}", wallet_name); if settings::test_indy_mode_enabled() { - unsafe { WALLET_HANDLE = 0;} - return Ok(()) + set_wallet_handle(0); + return Ok(()); } - match close_wallet() { - Ok(_) => (), - Err(x) => (), - }; + close_wallet().ok(); let config = settings::get_wallet_config(wallet_name, wallet_type, storage_config); - wallet::delete_wallet(&config,&settings::get_wallet_credentials(storage_creds)).wait().map_err(map_rust_indy_sdk_error) + wallet::delete_wallet(&config, &settings::get_wallet_credentials(storage_creds)) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn add_record(xtype: &str, id: &str, value: &str, tags: Option<&str>) -> Result<(), u32> { +pub fn add_record(xtype: &str, id: &str, value: &str, tags: Option<&str>) -> VcxResult<()> { trace!("add_record >>> xtype: {}, id: {}, value: {}, tags: {:?}", xtype, id, value, tags); - if settings::test_indy_mode_enabled() { return Ok(()) } + if settings::test_indy_mode_enabled() { return Ok(()); } wallet::add_wallet_record(get_wallet_handle(), xtype, id, value, tags) .wait() @@ -103,11 +106,11 @@ pub fn add_record(xtype: &str, id: &str, value: &str, tags: Option<&str>) -> Res } -pub fn get_record(xtype: &str, id: &str, options: &str) -> Result { +pub fn get_record(xtype: &str, id: &str, options: &str) -> VcxResult { trace!("get_record >>> xtype: {}, id: {}, options: {}", xtype, id, options); if settings::test_indy_mode_enabled() { - return Ok(r#"{"id":"123","type":"record type","value":"record value","tags":null}"#.to_string()) + return Ok(r#"{"id":"123","type":"record type","value":"record value","tags":null}"#.to_string()); } wallet::get_wallet_record(get_wallet_handle(), xtype, id, options) @@ -115,66 +118,66 @@ pub fn get_record(xtype: &str, id: &str, options: &str) -> Result { .map_err(map_rust_indy_sdk_error) } -pub fn delete_record(xtype: &str, id: &str) -> Result<(), u32> { +pub fn delete_record(xtype: &str, id: &str) -> VcxResult<()> { trace!("delete_record >>> xtype: {}, id: {}", xtype, id); - if settings::test_indy_mode_enabled() { return Ok(()) } + if settings::test_indy_mode_enabled() { return Ok(()); } + wallet::delete_wallet_record(get_wallet_handle(), xtype, id) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn update_record_value(xtype: &str, id: &str, value: &str) -> Result<(), u32> { +pub fn update_record_value(xtype: &str, id: &str, value: &str) -> VcxResult<()> { trace!("update_record_value >>> xtype: {}, id: {}, value: {}", xtype, id, value); - if settings::test_indy_mode_enabled() { return Ok(()) } + if settings::test_indy_mode_enabled() { return Ok(()); } + wallet::update_wallet_record_value(get_wallet_handle(), xtype, id, value) .wait() .map_err(map_rust_indy_sdk_error) } -pub fn export(wallet_handle: i32, path: &Path, backup_key: &str) -> Result<(), WalletError> { +pub fn export(wallet_handle: i32, path: &Path, backup_key: &str) -> VcxResult<()> { trace!("export >>> wallet_handle: {}, path: {:?}, backup_key: ****", wallet_handle, path); let export_config = json!({ "key": backup_key, "path": &path}).to_string(); - match wallet::export_wallet(wallet_handle, &export_config).wait() { - Ok(_) => Ok(()), - Err(e) => Err(WalletError::CommonError(map_rust_indy_sdk_error(e))), - } + wallet::export_wallet(wallet_handle, &export_config) + .wait() + .map_err(map_rust_indy_sdk_error) } -pub fn import(config: &str) -> Result<(), WalletError> { +pub fn import(config: &str) -> VcxResult<()> { trace!("import >>> config {}", config); - settings::process_config_string(config).map_err(|e| WalletError::CommonError(e))?; + settings::process_config_string(config)?; let key = settings::get_config_value(settings::CONFIG_WALLET_KEY) - .map_err(|e| WalletError::CommonError(e))?; + .or(Err(VcxError::from(VcxErrorKind::MissingWalletKey)))?; let name = settings::get_config_value(settings::CONFIG_WALLET_NAME) - .map_err(|e| WalletError::CommonError(error::MISSING_WALLET_NAME.code_num))?; + .or(Err(VcxError::from(VcxErrorKind::MissingWalletName)))?; let exported_wallet_path = settings::get_config_value(settings::CONFIG_EXPORTED_WALLET_PATH) - .or(Err(WalletError::CommonError(error::MISSING_EXPORTED_WALLET_PATH.code_num)))?; + .or(Err(VcxError::from(VcxErrorKind::MissingExportedWalletPath)))?; let backup_key = settings::get_config_value(settings::CONFIG_WALLET_BACKUP_KEY) - .or(Err(WalletError::CommonError(error::MISSING_BACKUP_KEY.code_num)))?; + .or(Err(VcxError::from(VcxErrorKind::MissingBackupKey)))?; let config = settings::get_wallet_config(&name, None, None); let credentials = settings::get_wallet_credentials(None); let import_config = json!({"key": backup_key, "path": exported_wallet_path }).to_string(); - match wallet::import_wallet(&config, &credentials, &import_config).wait() { - Ok(_) => Ok(()), - Err(e) => Err(WalletError::CommonError(map_rust_indy_sdk_error(e))), - } + wallet::import_wallet(&config, &credentials, &import_config) + .wait() + .map_err(map_rust_indy_sdk_error) } #[cfg(test)] pub mod tests { use super::*; - use utils::{get_temp_dir_path, error}; + use utils::{get_temp_dir_path}; use std::thread; use std::time::Duration; use utils::devsetup::tests::setup_wallet_env; @@ -221,14 +224,14 @@ pub mod tests { #[test] fn test_wallet() { init!("false"); - assert!( get_wallet_handle() > 0); - assert_eq!(error::INVALID_WALLET_CREATION.code_num, init_wallet(&String::from(""), None, None, None).unwrap_err()); + assert!(get_wallet_handle() > 0); + assert_eq!(VcxErrorKind::WalletCreate, init_wallet(&String::from(""), None, None, None).unwrap_err().kind()); } #[test] fn test_wallet_for_unknown_type() { init!("false"); - assert_eq!(error::INVALID_WALLET_CREATION.code_num, init_wallet("test_wallet_for_unknown_type", Some("UNKNOWN_WALLET_TYPE"), None, None).unwrap_err()); + assert_eq!(VcxErrorKind::WalletCreate, init_wallet("test_wallet_for_unknown_type", Some("UNKNOWN_WALLET_TYPE"), None, None).unwrap_err().kind()); } #[test] @@ -242,7 +245,7 @@ pub mod tests { // Open fails without Wallet Key Derivation set ::api::vcx::vcx_shutdown(false); - assert_eq!(open_wallet(wallet_n, None, None, None), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); + assert_eq!(open_wallet(wallet_n, None, None, None).unwrap_err().kind(), VcxErrorKind::UnknownLiibndyError); // Open works when set settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); @@ -251,7 +254,7 @@ pub mod tests { // Delete fails ::api::vcx::vcx_shutdown(false); - assert_eq!(delete_wallet(wallet_n, None, None, None), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); + assert_eq!(delete_wallet(wallet_n, None, None, None).unwrap_err().kind(), VcxErrorKind::UnknownLiibndyError); // Delete works settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); @@ -283,7 +286,7 @@ pub mod tests { open_wallet(&settings::DEFAULT_WALLET_NAME, None, None, None).unwrap(); // If wallet was successfully imported, there will be an error trying to add this duplicate record - assert_eq!(add_record(xtype, id, value, None), Err(error::DUPLICATE_WALLET_RECORD.code_num)); + assert_eq!(add_record(xtype, id, value, None).unwrap_err().kind(), VcxErrorKind::DuplicationWalletRecord); thread::sleep(Duration::from_secs(1)); ::api::vcx::vcx_shutdown(true); delete_import_wallet_path(export_path); @@ -291,29 +294,34 @@ pub mod tests { #[test] fn test_import_fails_with_missing_configs() { - settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"false"); + settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); ::api::vcx::vcx_shutdown(true); // Invalid json - assert_eq!(import(""), Err(WalletError::CommonError(error::INVALID_JSON.code_num))); + let res = import("").unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::InvalidJson); let mut config = json!({}); // Missing wallet_key - assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_WALLET_KEY.code_num))); + let res = import(&config.to_string()).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::MissingWalletKey); config[settings::CONFIG_WALLET_KEY] = serde_json::to_value("wallet_key1").unwrap(); // Missing wallet name - assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_WALLET_NAME.code_num))); + let res = import(&config.to_string()).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::MissingWalletName); config[settings::CONFIG_WALLET_NAME] = serde_json::to_value("wallet_name1").unwrap(); // Missing exported_wallet_path - assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_EXPORTED_WALLET_PATH.code_num))); + let res = import(&config.to_string()).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::MissingExportedWalletPath); config[settings::CONFIG_EXPORTED_WALLET_PATH] = serde_json::to_value( get_temp_dir_path(Some(settings::DEFAULT_EXPORTED_WALLET_PATH)).to_str().unwrap() ).unwrap(); // Missing backup_key - assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_BACKUP_KEY.code_num))); + let res = import(&config.to_string()).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::MissingBackupKey); } #[test] @@ -328,14 +336,15 @@ pub mod tests { settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); - assert_eq!(import(&import_config), Err(WalletError::CommonError(error::WALLET_ALREADY_EXISTS.code_num))); + let res = import(&import_config).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::DuplicationWallet); ::api::vcx::vcx_shutdown(true); delete_import_wallet_path(export_path); } #[test] - fn test_import_wallet_fails_with_invalid_path(){ + fn test_import_wallet_fails_with_invalid_path() { settings::set_defaults(); let wallet_name = "test_import_wallet_fails_with_invalid_path"; settings::set_config_value(settings::CONFIG_WALLET_NAME, wallet_name); @@ -350,7 +359,8 @@ pub mod tests { settings::CONFIG_EXPORTED_WALLET_PATH: "DIFFERENT_PATH", settings::CONFIG_WALLET_BACKUP_KEY: backup_key, }).to_string(); - assert_eq!(import(&import_config), Err(WalletError::CommonError(error::IOERROR.code_num))); + let res = import(&import_config).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::IOError); ::api::vcx::vcx_shutdown(true); delete_import_wallet_path(dir); @@ -374,7 +384,8 @@ pub mod tests { settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: bad_backup, }).to_string(); - assert_eq!(import(&import_config), Err(WalletError::CommonError(error::LIBINDY_INVALID_STRUCTURE.code_num))); + let res = import(&import_config).unwrap_err(); + assert_eq!(res.kind(), VcxErrorKind::LibindyInvalidStructure); ::api::vcx::vcx_shutdown(true); delete_import_wallet_path(export_path); @@ -403,7 +414,7 @@ pub mod tests { add_record(record_type, id, record, None).unwrap(); let rc = add_record(record_type, id, record, None); - assert_eq!(rc, Err(error::DUPLICATE_WALLET_RECORD.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::DuplicationWalletRecord); } #[test] @@ -434,7 +445,8 @@ pub mod tests { let wallet_n = "test_retrieve_missing_record_fails"; let rc = get_record(record_type, id, &options); - assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::WalletRecordNotFound); + } #[test] @@ -465,8 +477,7 @@ pub mod tests { let id = "123"; let rc = delete_record(record_type, id); - assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); - + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::WalletRecordNotFound); } #[test] @@ -486,7 +497,7 @@ pub mod tests { add_record(record_type, id, record, None).unwrap(); delete_record(record_type, id).unwrap(); let rc = get_record(record_type, id, &options); - assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::WalletRecordNotFound); } #[test] @@ -499,7 +510,7 @@ pub mod tests { let wallet_n = "test_update_record_value_fails_with_no_initial_record"; let rc = update_record_value(record_type, id, record); - assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); + assert_eq!(rc.unwrap_err().kind(), VcxErrorKind::WalletRecordNotFound); } #[test] diff --git a/vcx/libvcx/src/utils/logger.rs b/vcx/libvcx/src/utils/logger.rs index 634d0a9698..efaa3f46b0 100644 --- a/vcx/libvcx/src/utils/logger.rs +++ b/vcx/libvcx/src/utils/logger.rs @@ -22,7 +22,8 @@ use std::ffi::CString; #[cfg(target_os = "android")] use self::android_logger::Filter; use utils::cstring::CStringUtils; -use utils::error::LOGGING_ERROR; +use error::prelude::*; + use utils::libindy; @@ -60,12 +61,15 @@ impl LibvcxLogger { LibvcxLogger { context, enabled, log, flush } } - pub fn init(context: *const CVoid, enabled: Option, log: LogCB, flush: Option) -> Result<(), u32> { + pub fn init(context: *const CVoid, enabled: Option, log: LogCB, flush: Option) -> VcxResult<()> { trace!("LibvcxLogger::init >>>"); let logger = LibvcxLogger::new(context, enabled, log, flush); - log::set_boxed_logger(Box::new(logger)).map_err(|_| LOGGING_ERROR.code_num)?; + log::set_boxed_logger(Box::new(logger)) + .map_err(|err| VcxError::from_msg(VcxErrorKind::LoggingError, format!("Setting logger failed with: {}", err)))?; log::set_max_level(LevelFilter::Trace); - libindy::logger::set_logger(log::logger()).map_err(|_| LOGGING_ERROR.code_num)?; + libindy::logger::set_logger(log::logger()) + .map_err(|err| err.map(VcxErrorKind::LoggingError, "Setting logger failed"))?; + unsafe { LOGGER_STATE = LoggerState::Custom; CONTEXT = context; @@ -147,7 +151,7 @@ impl LibvcxDefaultLogger { } } - pub fn init(pattern: Option) -> Result<(), u32> { + pub fn init(pattern: Option) -> VcxResult<()> { trace!("LibvcxDefaultLogger::init >>> pattern: {:?}", pattern); let pattern = pattern.or(env::var("RUST_LOG").ok()); @@ -182,7 +186,7 @@ impl LibvcxDefaultLogger { Ok(_) => {} Err(e) => { error!("Error in logging init: {:?}", e); - return Err(LOGGING_ERROR.code_num); + return Err(VcxError::from_msg(VcxErrorKind::LoggingError, format!("Cannot init logger: {:?}", e))) } } } diff --git a/vcx/libvcx/src/utils/openssl.rs b/vcx/libvcx/src/utils/openssl.rs index b168a613d8..9ddda2f062 100644 --- a/vcx/libvcx/src/utils/openssl.rs +++ b/vcx/libvcx/src/utils/openssl.rs @@ -2,23 +2,25 @@ extern crate openssl; use self::openssl::sha::sha256; use self::openssl::bn::BigNum; use utils::error::BIG_NUMBER_ERROR; -pub fn encode(s: &str ) -> Result { +use error::prelude::*; + +pub fn encode(s: &str ) -> VcxResult { match s.parse::() { Ok(_) => Ok(s.to_string()), Err(_) => { let hash = sha256(s.as_bytes()); let bignum = match BigNum::from_slice(&hash) { Ok(b) => b, - Err(_) => { + Err(err) => { warn!("{}", BIG_NUMBER_ERROR.message); - return Err(BIG_NUMBER_ERROR.code_num) + return Err(VcxError::from_msg(VcxErrorKind::EncodeError, format!("Cannot encode string: {}", err))) } }; match bignum.to_dec_str() { Ok(s) => Ok(s.to_string()), - Err(_) => { + Err(err) => { warn!("{}", BIG_NUMBER_ERROR.message); - Err(BIG_NUMBER_ERROR.code_num) + return Err(VcxError::from_msg(VcxErrorKind::EncodeError, format!("Cannot encode string: {}", err))) } } } diff --git a/vcx/wrappers/ios/vcx/utils/NSError+VcxError.m b/vcx/wrappers/ios/vcx/utils/NSError+VcxError.m index abb8a9284d..56095a76fb 100644 --- a/vcx/wrappers/ios/vcx/utils/NSError+VcxError.m +++ b/vcx/wrappers/ios/vcx/utils/NSError+VcxError.m @@ -11,7 +11,27 @@ @implementation NSError (VcxError) + (NSError*) errorFromVcxError:(vcx_error_t) error { - return [NSError errorWithDomain:VcxErrorDomain code: error userInfo:nil]; + NSMutableDictionary *userInfo = [NSMutableDictionary new]; + + // if (error != Success) { + // const char * error_json_p; + // indy_get_current_error(&error_json_p); + // + // NSString *errorDetailsJson = [NSString stringWithUTF8String:error_json_p]; + // + // NSError *error; + // NSDictionary *errorDetails = [NSJSONSerialization JSONObjectWithData:[NSData dataWithBytes:[errorDetailsJson UTF8String] + // length:[errorDetailsJson length]] + // options:kNilOptions + // error: &error]; + // + // [userInfo setValue:errorDetails[@"error"] forKey:@"sdk_message"]; + // [userInfo setValue:errorDetails[@"message"] forKey:@"sdk_full_message"]; + // [userInfo setValue:errorDetails[@"cause"] forKey:@"sdk_cause"]; + // [userInfo setValue:errorDetails[@"backtrace"] forKey:@"sdk_backtrace"]; + // } + + return [NSError errorWithDomain:VcxErrorDomain code: error userInfo:userInfo]; } @end diff --git a/vcx/wrappers/ios/vcx/vcx.framework/Headers/libvcx.h b/vcx/wrappers/ios/vcx/vcx.framework/Headers/libvcx.h index 7329146a8d..c4c44abc77 100644 --- a/vcx/wrappers/ios/vcx/vcx.framework/Headers/libvcx.h +++ b/vcx/wrappers/ios/vcx/vcx.framework/Headers/libvcx.h @@ -68,6 +68,8 @@ vcx_error_t vcx_update_agent_info(vcx_command_handle_t handle, const char *info, const char *vcx_error_c_message(int); const char *vcx_version(); +vcx_error_t vcx_current_error(const char ** error_json_p); + /** * Schema object * diff --git a/vcx/wrappers/java/ci/android.dockerfile b/vcx/wrappers/java/ci/android.dockerfile index b4d25ad42c..f05d043939 100644 --- a/vcx/wrappers/java/ci/android.dockerfile +++ b/vcx/wrappers/java/ci/android.dockerfile @@ -21,5 +21,5 @@ RUN yes | .//home/android/android-sdk-linux/tools/bin/sdkmanager "ndk-bundle" RUN echo "android ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers USER android -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.31.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.32.0 ENV PATH /home/android/.cargo/bin:$PATH diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java index 0496c43a74..19b0f1873a 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/LibVcx.java @@ -1,6 +1,7 @@ package com.evernym.sdk.vcx; import com.sun.jna.*; +import com.sun.jna.ptr.PointerByReference; import java.io.File; @@ -30,7 +31,7 @@ public int vcx_init_with_config(int command_handle, * Helper API for testing purposes. */ public void vcx_set_next_agency_response(int msg); - + public void vcx_get_current_error(PointerByReference error); /** * Schema object diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxException.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxException.java index d69829c703..db373e393f 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxException.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxException.java @@ -61,6 +61,8 @@ import com.evernym.sdk.vcx.wallet.WalletItemAlreadyExistsException; import com.evernym.sdk.vcx.wallet.WalletItemNotFoundException; +import com.sun.jna.ptr.PointerByReference; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +74,10 @@ public class VcxException extends Exception { private static final Logger logger = LoggerFactory.getLogger("VcxException"); private static final long serialVersionUID = 2650355290834266234L; private int sdkErrorCode; + private String sdkMessage; + private String sdkFullMessage; + private String sdkCause; + private String sdkBacktrace; /** * Initializes a new VcxException with the specified message. @@ -81,6 +87,23 @@ public class VcxException extends Exception { protected VcxException(String message, int sdkErrorCode) { super(message); this.sdkErrorCode = sdkErrorCode; + setSdkErrorDetails(); + } + + private void setSdkErrorDetails(){ + PointerByReference errorDetailsJson = new PointerByReference(); + + LibVcx.api.vcx_get_current_error(errorDetailsJson); + + try { + JSONObject errorDetails = new JSONObject(errorDetailsJson.getValue().getString(0)); + this.sdkMessage = errorDetails.optString("error"); + this.sdkFullMessage = errorDetails.optString("message"); + this.sdkCause = errorDetails.optString("cause"); + this.sdkBacktrace = errorDetails.optString("backtrace"); + } catch(Exception e) { + // TODO + } } /** @@ -92,6 +115,34 @@ public int getSdkErrorCode() { return sdkErrorCode; } + /** + * Gets the SDK error message for the exception. + * + * @return The SDK error message used to construct the exception. + */ + public String getSdkMessage() {return sdkMessage;} + + /** + * Gets the SDK full error message for the exception. + * + * @return The SDK full error message used to construct the exception. + */ + public String getSdkFullMessage() {return sdkFullMessage;} + + /** + * Gets the SDK error cause for the exception. + * + * @return The SDK error cause used to construct the exception. + */ + public String getSdkCause() {return sdkCause;} + + /** + * Gets the SDK error backtrace for the exception. + * + * @return The SDK error backtrace used to construct the exception. + */ + public String getSdkBacktrace() {return sdkBacktrace;} + /** * Initializes a new VcxException using the specified SDK error code. * diff --git a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ErrorCodeTest.java b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ErrorCodeTest.java index 6e46146527..c7a28bfdd7 100644 --- a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ErrorCodeTest.java +++ b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ErrorCodeTest.java @@ -1,6 +1,9 @@ package com.evernym.sdk.vcx; +import com.evernym.sdk.vcx.connection.ConnectionApi; +import java9.util.concurrent.CompletableFuture; +import org.awaitility.Awaitility; import org.junit.jupiter.api.Test; import static com.evernym.sdk.vcx.ErrorCode.CONNECTION_ERROR; @@ -21,4 +24,17 @@ public void assertKnownErrorCodeisHandled(){ ErrorCode errorCode = ErrorCode.valueOf(1002); assertEquals(CONNECTION_ERROR,errorCode); } + + @Test + public void testGetErrorDetails(){ + try { + CompletableFuture future = ConnectionApi.connectionSerialize(0); + Awaitility.await().until(future::isDone); + } catch (VcxException e){ + assert(!e.getMessage().isEmpty()); + assert(!e.getSdkMessage().isEmpty()); + assert(!e.getSdkFullMessage().isEmpty()); + assert(!e.getSdkCause().isEmpty()); + } + } } diff --git a/vcx/wrappers/python3/tests/test_error.py b/vcx/wrappers/python3/tests/test_error.py index 8555920f5b..11d61ad531 100644 --- a/vcx/wrappers/python3/tests/test_error.py +++ b/vcx/wrappers/python3/tests/test_error.py @@ -1,4 +1,6 @@ import pytest + +from vcx.api.utils import vcx_agent_provision from vcx.error import ErrorCode, VcxError, error_message @@ -19,3 +21,13 @@ def test_all_error_codes(): assert(VcxError(max+1).error_msg == "Unknown Error") + +@pytest.mark.asyncio +@pytest.mark.usefixtures('vcx_init_test_mode') +async def test_error_details(): + with pytest.raises(VcxError) as e: + await vcx_agent_provision("") + assert ErrorCode.InvalidOption == e.value.error_code + assert e.value.error_msg + assert e.value.sdk_error_full_message + assert e.value.sdk_error_cause diff --git a/vcx/wrappers/python3/vcx/common.py b/vcx/wrappers/python3/vcx/common.py index ac4375f1ea..49c4eea0a3 100644 --- a/vcx/wrappers/python3/vcx/common.py +++ b/vcx/wrappers/python3/vcx/common.py @@ -3,7 +3,7 @@ import asyncio import itertools import logging -from .error import VcxError, ErrorCode +from .error import VcxError, ErrorCode, get_error_details from vcx.cdll import _cdll _futures = {} @@ -27,7 +27,8 @@ def do_call(name: str, *args): if err != ErrorCode.Success: logger.warning("_do_call: Function %s returned error %i", name, err) - future.set_exception(VcxError(ErrorCode(err))) + error_details = get_error_details() + future.set_exception(VcxError(ErrorCode(err), error_details)) logger.debug("do_call: <<< %s", future) return future @@ -52,7 +53,8 @@ def release(name, handle): if err != ErrorCode.Success: logger.warning("release: Function %s returned error %i", name, err) - raise VcxError(ErrorCode(err)) + error_details = get_error_details() + raise VcxError(ErrorCode(err), error_details) def get_version() -> str: @@ -84,7 +86,8 @@ def shutdown(delete_wallet: bool): err = do_call_sync(name, c_delete) if err != ErrorCode.Success: - raise VcxError(ErrorCode(err)) + error_details = get_error_details() + raise VcxError(ErrorCode(err), error_details) def mint_tokens(): @@ -97,27 +100,29 @@ def create_cb(cb_type: CFUNCTYPE, transform_fn=None): def _cb(command_handle: int, err: int, *args): if transform_fn: args = transform_fn(*args) - _cxs_callback(command_handle, err, *args) + error_details = get_error_details() if err != ErrorCode.Success else None + error = VcxError(ErrorCode(err), error_details) + _cxs_callback(command_handle, error, *args) res = cb_type(_cb) return res -def _cxs_callback(command_handle: int, err: int, *args): +def _cxs_callback(command_handle: int, err: VcxError, *args): (event_loop, future) = _futures[command_handle] event_loop.call_soon_threadsafe(_cxs_loop_callback, command_handle, err, *args) -def _cxs_loop_callback(command_handle: int, err, *args): +def _cxs_loop_callback(command_handle: int, err: VcxError, *args): (event_loop, future) = _futures.pop(command_handle) if future.cancelled(): print("_indy_loop_callback: Future was cancelled earlier") else: - if err != ErrorCode.Success: - future.set_exception(VcxError(ErrorCode(err))) + if err.error_code != ErrorCode.Success: + future.set_exception(err) else: if len(args) == 0: res = None diff --git a/vcx/wrappers/python3/vcx/error.py b/vcx/wrappers/python3/vcx/error.py index 35b9d78d39..494e9bf88c 100644 --- a/vcx/wrappers/python3/vcx/error.py +++ b/vcx/wrappers/python3/vcx/error.py @@ -1,8 +1,11 @@ +import json + LIBRARY = "libvcx.so" from vcx.cdll import _cdll from enum import IntEnum -from ctypes import c_char_p, cast, c_uint32 +from ctypes import c_char_p, byref, c_uint32 import logging +from typing import Optional class ErrorCode(IntEnum): @@ -55,7 +58,7 @@ class ErrorCode(IntEnum): InvalidMasterSecret = 1043, AlreadyInitialized = 1044, InvalidInviteDetails = 1045, - InvalidSelfAttestedVal = 1046, + InvalidSelfAttestedVal = 1046, InvalidPredicate = 1047, InvalidObjHandle = 1048, InvalidDisclosedProofHandle = 1049, @@ -109,10 +112,20 @@ class ErrorCode(IntEnum): class VcxError(Exception): # error_code: ErrorCode + # error_msg: Optional[str] - human-readable error description + # sdk_error_full_message: Optional[str] - vcx full error message. + # sdk_error_cause: Optional[str] - vcx error cause. + # sdk_error_backtrace: Optional[str] - vcx error backtrace. + # Collecting of backtrace can be enabled by setting environment variable `RUST_BACKTRACE=1` - def __init__(self, error_code: ErrorCode): + def __init__(self, error_code: ErrorCode, error_details: Optional[dict] = None): self.error_code = error_code self.error_msg = error_message(error_code) + if error_details: + self.error_msg = error_details['error'] + self.sdk_error_full_message = error_details['message'] + self.sdk_error_cause = error_details['cause'] + self.sdk_error_backtrace = error_details['backtrace'] def error_message(error_code: int) -> str: @@ -123,3 +136,15 @@ def error_message(error_code: int) -> str: err_msg = getattr(_cdll(), name)(c_error_code) logger.debug("error_message: Function %s[%s] returned error_message: %s", name, error_code, err_msg) return err_msg.decode() + + +def get_error_details() -> Optional[dict]: + logger = logging.getLogger(__name__) + logger.debug("get_error_details: >>>") + + error_c = c_char_p() + getattr(_cdll(), 'vcx_get_current_error')(byref(error_c)) + error_details = json.loads(error_c.value.decode()) if error_c.value else None + + logger.debug("get_error_details: <<< error_details: %s", error_details) + return error_details diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Ledger/LedgerBuildRequest.mm b/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Ledger/LedgerBuildRequest.mm index 690bc320aa..0718ff437a 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Ledger/LedgerBuildRequest.mm +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Ledger/LedgerBuildRequest.mm @@ -641,4 +641,42 @@ - (void)testBuildGetTxnRequest { XCTAssertTrue([getTxnRequest contains:expectedResult], @"getTxnRequest json doesn't contain expectedResult json"); } +// MARK: Auth Rule request + +- (void)testBuildAuthRuleRequestsWorks { + NSDictionary *constraint = @{ + @"sig_count": @(1), + @"role": @"0", + @"constraint_id": @"ROLE", + @"need_to_be_owner": @(false) + }; + + NSDictionary *expectedResult = @{ + @"identifier": [TestUtils trusteeDid], + @"operation": @{ + @"type": @"120", + @"auth_type": @"1", + @"auth_action": @"ADD", + @"field": @"role", + @"new_value": @"101", + @"constraint": constraint, + } + }; + + NSString *requestJson; + ret = [[LedgerUtils sharedInstance] buildAuthRuleRequestWithSubmitterDid:[TestUtils trusteeDid] + txnType:@"NYM" + action:@"ADD" + field:@"role" + oldValue:nil + newValue:@"101" + constraint:[NSDictionary toString:constraint] + outRequest:&requestJson]; + XCTAssertEqual(ret.code, Success, @"LedgerUtils::buildNymRequestWithSubmitterDid() failed!"); + + NSDictionary *request = [NSDictionary fromString:requestJson]; + + XCTAssertTrue([request contains:expectedResult], @"Request doesn't contain expectedResult"); +} + @end diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.h b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.h index b01cba99e1..e08516828d 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.h +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.h @@ -179,6 +179,16 @@ requestJson:(NSString *)requestJson resultJson:(NSString **)resultJson; +// MARK: - Auth Rule request +- (NSError *)buildAuthRuleRequestWithSubmitterDid:(NSString *)submitterDid + txnType:(NSString *)txnType + action:(NSString *)action + field:(NSString *)field + oldValue:(NSString *)oldValue + newValue:(NSString *)newValue + constraint:(NSString *)constraint + outRequest:(NSString **)resultJson; + // MARK: - Response Metadata - (NSError *)getResponseMetadata:(NSString *)response responseMetadata:(NSString **)responseMetadata; diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.mm b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.mm index c99724d7fb..5414042ecb 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.mm +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/LedgerUtils.mm @@ -729,6 +729,38 @@ - (NSError *)multiSignRequestWithWalletHandle:(IndyHandle)walletHandle return err; } +- (NSError *)buildAuthRuleRequestWithSubmitterDid:(NSString *)submitterDid + txnType:(NSString *)txnType + action:(NSString *)action + field:(NSString *)field + oldValue:(NSString *)oldValue + newValue:(NSString *)newValue + constraint:(NSString *)constraint + outRequest:(NSString **)resultJson { + XCTestExpectation *completionExpectation = [[XCTestExpectation alloc] initWithDescription:@"completion finished"]; + __block NSError *err = nil; + __block NSString *outJson = nil; + + [IndyLedger buildAuthRuleRequestWithSubmitterDid:submitterDid + txnType:txnType + action:action + field:field + oldValue:oldValue + newValue:newValue + constraint:constraint + completion:^(NSError *error, NSString *json) { + err = error; + outJson = json; + [completionExpectation fulfill]; + }]; + + [self waitForExpectations:@[completionExpectation] timeout:[TestUtils longTimeout]]; + + if (resultJson) {*resultJson = outJson;} + + return err; +} + - (NSError *)getResponseMetadata:(NSString *)response responseMetadata:(NSString **)responseMetadata { XCTestExpectation *completionExpectation = [[XCTestExpectation alloc] initWithDescription:@"completion finished"]; diff --git a/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.h b/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.h index 66464febda..edafeaaf9f 100644 --- a/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.h +++ b/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.h @@ -568,7 +568,45 @@ */ + (void)parseGetRevocRegDeltaResponse:(NSString *)getRevocRegDeltaResponse completion:(void (^)(NSError *error, NSString *revocRegDefId, NSString *revocRegDeltaJson, NSNumber *timestamp))completion; - + +// MARK: - Auth Rule request + +/** + Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + + @param submitterDid DID of the submitter stored in secured Wallet. + @param txnType - ledger transaction alias or associated value. + @param action - type of an action. + Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). + @param field - transaction field. + @param oldValue - old value of a field, which can be changed to a new_value (mandatory for EDIT action). + @param newValue - new value that can be used to fill the field. + @param constraint - set of constraints required for execution of an action in the following format: + { + constraint_id - type of a constraint. + Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + role - role of a user which satisfy to constrain. + sig_count - the number of signatures required to execution action. + need_to_be_owner - if user must be an owner of transaction. + metadata - additional parameters of the constraint. + } + can be combined by + { + 'constraint_id': <"AND" or "OR"> + 'auth_constraints': [, ] + } + + @param completion Callback that takes command result as parameter. Returns request result as json. + */ ++ (void)buildAuthRuleRequestWithSubmitterDid:(NSString *)submitterDid + txnType:(NSString *)txnType + action:(NSString *)action + field:(NSString *)field + oldValue:(NSString *)oldValue + newValue:(NSString *)newValue + constraint:(NSString *)constraint + completion:(void (^)(NSError *error, NSString *requestJSON))completion; + /** Parse transaction response to fetch metadata. The important use case for this method is validation of Node's response freshens. diff --git a/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.mm b/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.mm index 2d373124b7..40e7af3125 100644 --- a/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.mm +++ b/wrappers/ios/libindy-pod/Indy/Wrapper/IndyLedger.mm @@ -706,6 +706,37 @@ + (void)parseGetRevocRegDeltaResponse:(NSString *)getRevocRegDeltaResponse } } ++ (void)buildAuthRuleRequestWithSubmitterDid:(NSString *)submitterDid + txnType:(NSString *)txnType + action:(NSString *)action + field:(NSString *)field + oldValue:(NSString *)oldValue + newValue:(NSString *)newValue + constraint:(NSString *)constraint + completion:(void (^)(NSError *error, NSString *requestJSON))completion { + indy_error_t ret; + + indy_handle_t handle = [[IndyCallbacks sharedInstance] createCommandHandleFor:completion]; + + + ret = indy_build_auth_rule_request(handle, + [submitterDid UTF8String], + [txnType UTF8String], + [action UTF8String], + [field UTF8String], + [oldValue UTF8String], + [newValue UTF8String], + [constraint UTF8String], + IndyWrapperCommonStringCallback); + if (ret != Success) { + [[IndyCallbacks sharedInstance] deleteCommandHandleFor:handle]; + + dispatch_async(dispatch_get_main_queue(), ^{ + completion([NSError errorFromIndyError:ret], nil); + }); + } +} + + (void)getResponseMetadata:(NSString *)response completion:(void (^)(NSError *error, NSString *responseMetadata))completion { indy_error_t ret; diff --git a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java index 76daa98324..06470f85ea 100644 --- a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java +++ b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/LibIndy.java @@ -70,6 +70,7 @@ public interface API extends Library { public int indy_build_get_revoc_reg_delta_request(int command_handle, String submitter_did, String revoc_reg_def_id, long from, long to, Callback cb); public int indy_parse_get_revoc_reg_delta_response(int command_handle, String get_revoc_reg_delta_response, Callback cb); public int indy_get_response_metadata(int command_handle, String response, Callback cb); + public int indy_build_auth_rule_request(int command_handle, String submitter_did, String txn_type, String action, String field, String old_value, String new_value, String constraint, Callback cb); // did.rs diff --git a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java index c936466f7d..a2782e4212 100644 --- a/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java +++ b/wrappers/java/src/main/java/org/hyperledger/indy/sdk/ledger/Ledger.java @@ -1265,4 +1265,64 @@ public static CompletableFuture getResponseMetadata( return future; } + + /** + * Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + * + * @param submitterDid DID of the submitter stored in secured Wallet. + * @param txnType - ledger transaction alias or associated value. + * @param action - type of an action. + * Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). + * @param field - transaction field. + * @param oldValue - old value of a field, which can be changed to a new_value (mandatory for EDIT action). + * @param newValue - new value that can be used to fill the field. + * @param constraint - set of constraints required for execution of an action in the following format: + * { + * constraint_id - [string] type of a constraint. + * Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + * role - [string] role of a user which satisfy to constrain. + * sig_count - [u32] the number of signatures required to execution action. + * need_to_be_owner - [bool] if user must be an owner of transaction. + * metadata - [object] additional parameters of the constraint. + * } + * can be combined by + * { + * 'constraint_id': "AND" or "OR" + * 'auth_constraints': [[constraint_1], [constraint_2]] + * } + + * @return A future resolving to a request result as json. + * @throws IndyException Thrown if an error occurs when calling the underlying SDK. + */ + public static CompletableFuture buildAuthRuleRequest( + String submitterDid, + String txnType, + String action, + String field, + String oldValue, + String newValue, + String constraint) throws IndyException { + + ParamGuard.notNullOrWhiteSpace(submitterDid, "submitterDid"); + ParamGuard.notNullOrWhiteSpace(txnType, "txnType"); + ParamGuard.notNullOrWhiteSpace(action, "action"); + + CompletableFuture future = new CompletableFuture(); + int commandHandle = addFuture(future); + + int result = LibIndy.api.indy_build_auth_rule_request( + commandHandle, + submitterDid, + txnType, + action, + field, + oldValue, + newValue, + constraint, + buildRequestCb); + + checkResult(future, result); + + return future; + } } diff --git a/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/AuthRuleRequestsTest.java b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/AuthRuleRequestsTest.java new file mode 100644 index 0000000000..b71b49d258 --- /dev/null +++ b/wrappers/java/src/test/java/org/hyperledger/indy/sdk/ledger/AuthRuleRequestsTest.java @@ -0,0 +1,65 @@ +package org.hyperledger.indy.sdk.ledger; + +import org.hyperledger.indy.sdk.IndyIntegrationTest; +import org.json.JSONObject; +import org.junit.Test; + +public class AuthRuleRequestsTest extends IndyIntegrationTest { + + private String txnType = "NYM"; + private String field = "role"; + private String newValue = "101"; + private JSONObject constraint = new JSONObject() + .put("sig_count", 1) + .put("role", "0") + .put("constraint_id", "ROLE") + .put("need_to_be_owner", false); + + @Test + public void testBuildAuthRuleRequestWorksForAddAction() throws Exception { + String addAuthAction = "ADD"; + + JSONObject expectedResult = new JSONObject() + .put("identifier", DID) + .put("operation", + new JSONObject() + .put("type", "120") + .put("auth_type", "1") + .put("auth_action", addAuthAction) + .put("field", field) + .put("new_value", newValue) + .put("constraint", constraint) + ); + + String request = Ledger.buildAuthRuleRequest(DID, txnType, addAuthAction, field, null, newValue, constraint.toString()).get(); + + assert (new JSONObject(request).toMap().entrySet() + .containsAll( + expectedResult.toMap().entrySet())); + } + + @Test + public void testBuildAuthRuleRequestWorksForEditAction() throws Exception { + String editAuthAction = "EDIT"; + String oldValue = "0"; + + JSONObject expectedResult = new JSONObject() + .put("identifier", DID) + .put("operation", + new JSONObject() + .put("type", "120") + .put("auth_type", "1") + .put("auth_action", editAuthAction) + .put("field", field) + .put("old_value", oldValue) + .put("new_value", newValue) + .put("constraint", constraint) + ); + + String request = Ledger.buildAuthRuleRequest(DID, txnType, editAuthAction, field, oldValue, newValue, constraint.toString()).get(); + + assert (new JSONObject(request).toMap().entrySet() + .containsAll( + expectedResult.toMap().entrySet())); + } +} diff --git a/wrappers/nodejs/README.md b/wrappers/nodejs/README.md index b7c197aa1b..be942cb166 100644 --- a/wrappers/nodejs/README.md +++ b/wrappers/nodejs/README.md @@ -1748,6 +1748,38 @@ Parse a GET\_REVOC\_REG\_DELTA response to get Revocation Registry Delta in the Errors: `Common*` +#### buildAuthRuleRequest \( submitterDid, txnType, action, field, oldValue, newValue, constraint \) -> request + +Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + +* `submitterDid`: String - \(Optional\) DID of the read request sender \(if not provided then default Libindy DID will be used\). +* `txnType`: String - ledger transaction alias or associated value. +* `action`: String - type of an action. + * "ADD" - to add a new rule + * "EDIT" - to edit an existing one +* `field`: String - transaction field. +* `oldValue`: String - \(Optional\) old value of a field, which can be changed to a new_value (mandatory for EDIT action). +* `newValue`: String - new value that can be used to fill the field. +* `constraint`: String - set of constraints required for execution of an action in the following format: +``` + { + constraint_id - type of a constraint. + Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + role - role of a user which satisfy to constrain. + sig_count - the number of signatures required to execution action. + need_to_be_owner - if user must be an owner of transaction. + metadata - additional parameters of the constraint. + } +can be combined by + { + 'constraint_id': <"AND" or "OR"> + 'auth_constraints': [, ] + } +``` +* __->__ `request`: Json + +Errors: `Common*` + #### getResponseMetadata \( response \) -> responseMetadata Parse transaction response to fetch metadata. diff --git a/wrappers/nodejs/src/index.js b/wrappers/nodejs/src/index.js index 2614cd899c..b351e21fc1 100644 --- a/wrappers/nodejs/src/index.js +++ b/wrappers/nodejs/src/index.js @@ -541,6 +541,12 @@ indy.parseGetRevocRegDeltaResponse = function parseGetRevocRegDeltaResponse (get return cb.promise } +indy.buildAuthRuleRequest = function buildAuthRuleRequest (submitterDid, txnType, action, field, oldValue, newValue, constraint, cb) { + cb = wrapIndyCallback(cb, fromJson) + capi.buildAuthRuleRequest(submitterDid, txnType, action, field, oldValue, newValue, toJson(constraint), cb) + return cb.promise +} + indy.getResponseMetadata = function getResponseMetadata (response, cb) { cb = wrapIndyCallback(cb, fromJson) capi.getResponseMetadata(toJson(response), cb) diff --git a/wrappers/nodejs/src/indy.cc b/wrappers/nodejs/src/indy.cc index b0a1228d3e..da4698f82d 100644 --- a/wrappers/nodejs/src/indy.cc +++ b/wrappers/nodejs/src/indy.cc @@ -2038,6 +2038,40 @@ NAN_METHOD(parseGetRevocRegDeltaResponse) { delete arg0; } +void buildAuthRuleRequest_cb(indy_handle_t handle, indy_error_t xerr, const char* arg0) { + IndyCallback* icb = IndyCallback::getCallback(handle); + if(icb != nullptr){ + icb->cbString(xerr, arg0); + } +} +NAN_METHOD(buildAuthRuleRequest) { + INDY_ASSERT_NARGS(buildAuthRuleRequest, 8) + INDY_ASSERT_STRING(buildAuthRuleRequest, 0, submitterDid) + INDY_ASSERT_STRING(buildAuthRuleRequest, 1, txnType) + INDY_ASSERT_STRING(buildAuthRuleRequest, 2, action) + INDY_ASSERT_STRING(buildAuthRuleRequest, 3, field) + INDY_ASSERT_STRING(buildAuthRuleRequest, 4, oldValue) + INDY_ASSERT_STRING(buildAuthRuleRequest, 5, newValue) + INDY_ASSERT_STRING(buildAuthRuleRequest, 6, constraint) + INDY_ASSERT_FUNCTION(buildAuthRuleRequest, 7) + const char* arg0 = argToCString(info[0]); + const char* arg1 = argToCString(info[1]); + const char* arg2 = argToCString(info[2]); + const char* arg3 = argToCString(info[3]); + const char* arg4 = argToCString(info[4]); + const char* arg5 = argToCString(info[5]); + const char* arg6 = argToCString(info[6]); + IndyCallback* icb = argToIndyCb(info[7]); + indyCalled(icb, indy_build_auth_rule_request(icb->handle, arg0, arg1, arg2, arg3, arg4, arg5, arg6, buildAuthRuleRequest_cb)); + delete arg0; + delete arg1; + delete arg2; + delete arg3; + delete arg4; + delete arg5; + delete arg6; +} + void getResponseMetadata_cb(indy_handle_t handle, indy_error_t xerr, const char* arg0) { IndyCallback* icb = IndyCallback::getCallback(handle); if(icb != nullptr){ @@ -3115,6 +3149,7 @@ NAN_MODULE_INIT(InitAll) { Nan::Export(target, "parseGetRevocRegResponse", parseGetRevocRegResponse); Nan::Export(target, "buildGetRevocRegDeltaRequest", buildGetRevocRegDeltaRequest); Nan::Export(target, "parseGetRevocRegDeltaResponse", parseGetRevocRegDeltaResponse); + Nan::Export(target, "buildAuthRuleRequest", buildAuthRuleRequest); Nan::Export(target, "getResponseMetadata", getResponseMetadata); Nan::Export(target, "addWalletRecord", addWalletRecord); Nan::Export(target, "updateWalletRecordValue", updateWalletRecordValue); diff --git a/wrappers/nodejs/test/ledger.js b/wrappers/nodejs/test/ledger.js index 28cbb857a9..9883c07e45 100644 --- a/wrappers/nodejs/test/ledger.js +++ b/wrappers/nodejs/test/ledger.js @@ -151,6 +151,17 @@ test('ledger', async function (t) { req = await indy.signRequest(wh, myDid, req) res = await indy.submitAction(pool.handle, req, null, null) + var constraint = { + 'sig_count': 1, + 'metadata': {}, + 'role': '0', + 'constraint_id': 'ROLE', + 'need_to_be_owner': false + } + req = await indy.buildAuthRuleRequest(trusteeDid, 'NYM', 'ADD', 'role', null, '101', constraint) + res = await indy.signAndSubmitRequest(pool.handle, wh, trusteeDid, req) + t.is(res.op, 'REPLY') + await indy.closeWallet(wh) await indy.deleteWallet(walletConfig, walletCredentials) pool.cleanup() diff --git a/wrappers/python/indy/ledger.py b/wrappers/python/indy/ledger.py index 8700d60682..8928d47bd9 100644 --- a/wrappers/python/indy/ledger.py +++ b/wrappers/python/indy/ledger.py @@ -1261,3 +1261,76 @@ async def get_response_metadata(response: str) -> str: res = response_metadata.decode() logger.debug("get_response_metadata: <<< res: %r", res) return res + + +async def build_auth_rule_request(submitter_did: str, + txn_type: str, + action: str, + field: str, + old_value: Optional[str], + new_value: str, + constraint: str) -> str: + """ + Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. + + :param submitter_did: DID of the submitter stored in secured Wallet. + :param txn_type: ledger transaction alias or associated value. + :param action: type of an action. + Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). + :param field: transaction field. + :param old_value: old value of a field, which can be changed to a new_value (mandatory for EDIT action). + :param new_value: new value that can be used to fill the field. + :param constraint: set of constraints required for execution of an action in the following format: + { + constraint_id - type of a constraint. + Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. + role - role of a user which satisfy to constrain. + sig_count - the number of signatures required to execution action. + need_to_be_owner - if user must be an owner of transaction. + metadata - additional parameters of the constraint. + } + can be combined by + { + 'constraint_id': <"AND" or "OR"> + 'auth_constraints': [, ] + } + + :return: Request result as json. + """ + + logger = logging.getLogger(__name__) + logger.debug("build_auth_rule_request: >>> submitter_did: %r, txn_type: %r, action: %r, field: %r, " + "old_value: %r, new_value: %r, constraint: %r", + submitter_did, + txn_type, + action, + field, + old_value, + new_value, + constraint) + + if not hasattr(build_auth_rule_request, "cb"): + logger.debug("build_auth_rule_request: Creating callback") + build_auth_rule_request.cb = create_cb(CFUNCTYPE(None, c_int32, c_int32, c_char_p)) + + c_submitter_did = c_char_p(submitter_did.encode('utf-8')) + c_txn_type = c_char_p(txn_type.encode('utf-8')) + c_action = c_char_p(action.encode('utf-8')) + c_field = c_char_p(field.encode('utf-8')) + c_old_value = c_char_p(old_value.encode('utf-8')) if old_value is not None else None + c_new_value = c_char_p(new_value.encode('utf-8')) + c_constraint = c_char_p(constraint.encode('utf-8')) + + request_json = await do_call('indy_build_auth_rule_request', + c_submitter_did, + c_txn_type, + c_action, + c_field, + c_old_value, + c_new_value, + c_constraint, + build_auth_rule_request.cb) + + res = request_json.decode() + logger.debug("build_auth_rule_request: <<< res: %r", res) + return res diff --git a/wrappers/python/tests/ledger/test_build_auth_rule_request.py b/wrappers/python/tests/ledger/test_build_auth_rule_request.py new file mode 100644 index 0000000000..aebe92a5dd --- /dev/null +++ b/wrappers/python/tests/ledger/test_build_auth_rule_request.py @@ -0,0 +1,61 @@ +from indy import ledger +from indy.error import * + +import json +import pytest + +identifier = "Th7MpTaRZVRYnPiabds81Y" +txn_type = "NYM" +add_auth_action = "ADD" +edit_auth_action = "EDIT" +field = 'role' +old_value = '0' +new_value = '101' +constraint = { + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": False +} + + +@pytest.mark.asyncio +async def test_build_auth_rule_request_works_for_add_auth_action(): + expected_request = { + "identifier": identifier, + "operation": { + "type": "120", + "auth_type": "1", + "auth_action": add_auth_action, + "field": field, + "new_value": new_value, + "constraint": constraint + } + } + + request = json.loads( + await ledger.build_auth_rule_request(identifier, txn_type, add_auth_action, field, None, new_value, + json.dumps(constraint))) + assert expected_request.items() <= request.items() + + +@pytest.mark.asyncio +async def test_build_auth_rule_request_works_for_edit_auth_action(): + expected_request = { + "identifier": identifier, + "operation": { + "type": "120", + "auth_type": "1", + "auth_action": edit_auth_action, + "field": field, + "old_value": old_value, + "new_value": new_value, + "constraint": constraint + } + } + + request = json.loads( + await ledger.build_auth_rule_request(identifier, txn_type, edit_auth_action, field, old_value, new_value, + json.dumps(constraint))) + assert expected_request.items() <= request.items() diff --git a/wrappers/rust/indy-sys/src/ledger.rs b/wrappers/rust/indy-sys/src/ledger.rs index f76620284c..7d0b784c51 100644 --- a/wrappers/rust/indy-sys/src/ledger.rs +++ b/wrappers/rust/indy-sys/src/ledger.rs @@ -221,6 +221,17 @@ extern { pub fn indy_get_response_metadata(command_handle: Handle, response: CString, cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_auth_rule_request(command_handle: Handle, + submitter_did: CString, + txn_type: CString, + action: CString, + field: CString, + old_value: CString, + new_value: CString, + constraint: CString, + cb: Option) -> Error; } pub type CustomTransactionParser = extern fn(reply_from_node: CString, parsed_sp: *mut CString) -> Error; diff --git a/wrappers/rust/src/ledger.rs b/wrappers/rust/src/ledger.rs index 3d8aa37807..cf23e3fe41 100644 --- a/wrappers/rust/src/ledger.rs +++ b/wrappers/rust/src/ledger.rs @@ -85,7 +85,7 @@ fn _submit_action(command_handle: IndyHandle, pool_handle: IndyHandle, request_j let nodes_str = opt_c_str!(nodes); ErrorCode::from(unsafe { - ledger::indy_submit_action(command_handle, pool_handle, request_json.as_ptr(), opt_c_ptr!(nodes, nodes_str), wait_timeout.unwrap_or(-1), cb) + ledger::indy_submit_action(command_handle, pool_handle, request_json.as_ptr(), opt_c_ptr!(nodes, nodes_str), wait_timeout.unwrap_or(-1), cb) }) } @@ -259,7 +259,7 @@ pub fn build_get_txn_request(submitter_did: Option<&str>, ledger_type: Option<&s ResultHandler::str(command_handle, err, receiver) } -fn _build_get_txn_request(command_handle: IndyHandle, submitter_did: Option<&str>, ledger_type: Option<&str>, seq_no: i32, cb: Option) -> ErrorCode { +fn _build_get_txn_request(command_handle: IndyHandle, submitter_did: Option<&str>, ledger_type: Option<&str>, seq_no: i32, cb: Option) -> ErrorCode { let submitter_did_str = opt_c_str!(submitter_did); let ledger_type_str = opt_c_str!(ledger_type); @@ -566,7 +566,7 @@ fn _build_get_validator_info_request(command_handle: IndyHandle, submitter_did: let submitter_did = c_str!(submitter_did); ErrorCode::from(unsafe { - ledger::indy_build_get_validator_info_request(command_handle, submitter_did.as_ptr(), cb) + ledger::indy_build_get_validator_info_request(command_handle, submitter_did.as_ptr(), cb) }) } @@ -890,7 +890,7 @@ pub fn parse_get_revoc_reg_response(get_revoc_reg_response: &str) -> Box) -> ErrorCode { let get_revoc_reg_response = c_str!(get_revoc_reg_response); - ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_response(command_handle,get_revoc_reg_response.as_ptr(), cb) }) + ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_response(command_handle, get_revoc_reg_response.as_ptr(), cb) }) } /// Builds a GET_REVOC_REG_DELTA request. Request to get the delta of the accumulated state of the Revocation Registry. @@ -947,7 +947,7 @@ pub fn parse_get_revoc_reg_delta_response(get_revoc_reg_delta_response: &str) -> fn _parse_get_revoc_reg_delta_response(command_handle: IndyHandle, get_revoc_reg_delta_response: &str, cb: Option) -> ErrorCode { let get_revoc_reg_delta_response = c_str!(get_revoc_reg_delta_response); - ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_delta_response(command_handle,get_revoc_reg_delta_response.as_ptr(), cb) }) + ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_delta_response(command_handle, get_revoc_reg_delta_response.as_ptr(), cb) }) } /// Parse transaction response to fetch metadata. @@ -991,5 +991,71 @@ pub fn get_response_metadata(response: &str) -> Box) -> ErrorCode { let response = c_str!(response); - ErrorCode::from(unsafe { ledger::indy_get_response_metadata(command_handle,response.as_ptr(), cb) }) + ErrorCode::from(unsafe { ledger::indy_get_response_metadata(command_handle, response.as_ptr(), cb) }) } + +/// Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. +/// +/// # Arguments +/// * `txn_type`: ledger transaction alias or associated value for which authentication rules will be applied. +/// * `field`: type of an action for which authentication rules will be applied. +/// Can be either "ADD" (to add a new rule) or "EDIT" (to edit an existing one). +/// * `action`: transaction field for which authentication rule will be applied. +/// * `old_value`: old value of a field, which can be changed to a new_value (mandatory for EDIT action). +/// * `new_value`: new value that can be used to fill the field. +/// * `constraint`: set of constraints required for execution of an action in the following format: +/// { +/// constraint_id - type of a constraint. +/// Can be either "ROLE" to specify final constraint or "AND"/"OR" to combine constraints. +/// role - role of a user which satisfy to constrain. +/// sig_count - the number of signatures required to execution action. +/// need_to_be_owner - if user must be an owner of transaction. +/// metadata - additional parameters of the constraint. +/// } +/// can be combined by +/// { +/// 'constraint_id': <"AND" or "OR"> +/// 'auth_constraints': [, ] +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_auth_rule_request(submitter_did: &str, txn_type: &str, action: &str, field: &str, + old_value: Option<&str>, new_value: &str, constraint: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_auth_rule_request(command_handle, submitter_did, txn_type, action, field, old_value, new_value, constraint, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_auth_rule_request(command_handle: IndyHandle, + submitter_did: &str, + txn_type: &str, + action: &str, + field: &str, + old_value: Option<&str>, + new_value: &str, + constraint: &str, + cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let txn_type = c_str!(txn_type); + let action = c_str!(action); + let field = c_str!(field); + let new_value = c_str!(new_value); + let constraint = c_str!(constraint); + + let old_value_str = opt_c_str!(old_value); + + ErrorCode::from(unsafe { + ledger::indy_build_auth_rule_request(command_handle, + submitter_did.as_ptr(), + txn_type.as_ptr(), + action.as_ptr(), + field.as_ptr(), + opt_c_ptr!(old_value, old_value_str), + new_value.as_ptr(), + constraint.as_ptr(), + cb) + }) +} \ No newline at end of file diff --git a/wrappers/rust/tests/ledger.rs b/wrappers/rust/tests/ledger.rs index 52c2115f81..fa9211796b 100644 --- a/wrappers/rust/tests/ledger.rs +++ b/wrappers/rust/tests/ledger.rs @@ -1,9 +1,12 @@ -#[macro_use] extern crate serde_json; -#[macro_use] extern crate serde_derive; +#[macro_use] +extern crate serde_json; +#[macro_use] +extern crate serde_derive; extern crate rmp_serde; extern crate byteorder; extern crate indyrs as indy; extern crate futures; + #[allow(unused_variables)] #[allow(unused_macros)] #[allow(dead_code)] @@ -133,7 +136,7 @@ mod test_submit_request { mod test_submit_action { use super::*; - const NODES : &str = "[\"Node1\", \"Node2\"]"; + const NODES: &str = "[\"Node1\", \"Node2\"]"; #[test] #[ignore] // TODO: restore after IS-1027 will be fixed @@ -407,7 +410,7 @@ mod test_build_get_attrib_request { mod test_build_schema_request { use super::*; - const SCHEMA_DATA : &str = r#"{"id":"id","attrNames": ["name", "male"],"name":"gvt2","version":"3.1","ver":"1.0"}"#; + const SCHEMA_DATA: &str = r#"{"id":"id","attrNames": ["name", "male"],"name":"gvt2","version":"3.1","ver":"1.0"}"#; #[test] pub fn build_schema_request_success() { @@ -425,9 +428,9 @@ mod test_build_schema_request { #[cfg(test)] mod test_build_get_schema_request { -use super::*; + use super::*; - const SCHEMA_REQUEST : &str = "5LEV4bTAXntXqmtLFm7yCS:2:bob:1.0"; + const SCHEMA_REQUEST: &str = "5LEV4bTAXntXqmtLFm7yCS:2:bob:1.0"; #[test] pub fn build_get_schema_request_success() { @@ -450,11 +453,11 @@ mod test_parse_get_schema_response { use super::*; - const SCHEMA_NAME : &str = "schema_1234"; - const SCHEMA_DATA : &str = r#"{"id":"schema_id1234","attrNames": ["name", "male"],"name":"schema_1234","version":"1.0","ver":"1.0"}"#; + const SCHEMA_NAME: &str = "schema_1234"; + const SCHEMA_DATA: &str = r#"{"id":"schema_id1234","attrNames": ["name", "male"],"name":"schema_1234","version":"1.0","ver":"1.0"}"#; - fn create_build_schema_request(did : &String) -> String { + fn create_build_schema_request(did: &String) -> String { format!("{}:2:{}:1.0", did, SCHEMA_NAME) } @@ -483,7 +486,7 @@ mod test_parse_get_schema_response { let schema_request = create_build_schema_request(&did); let schema_response = ledger::build_get_schema_request(Some(&did), &schema_request).wait().unwrap(); - let signed_response = ledger::sign_request(wallet.handle, &did,&schema_response).wait().unwrap(); + let signed_response = ledger::sign_request(wallet.handle, &did, &schema_response).wait().unwrap(); let submit_response = ledger::submit_request(pool_handle, &signed_response).wait().unwrap(); let parse_response = ledger::parse_get_schema_response(&submit_response).wait(); @@ -522,7 +525,7 @@ mod test_build_get_ddo_request { mod test_build_get_txn_request { use super::*; - const LEDGER_TYPE : &str = "DOMAIN"; + const LEDGER_TYPE: &str = "DOMAIN"; #[test] pub fn build_get_txn_request_success() { @@ -542,10 +545,10 @@ mod test_build_get_txn_request { mod test_build_cred_def_request { use super::*; - const CRED_DATA : &str = r#"{"ver":"1.0","id":"V4SGRU86Z58d6TV7PBUe6f:3:CL:17:oI6Iokv","schemaId":"17","type":"CL","tag":"oI6Iokv","value":{"primary":{"n":"87178281071734731437690387382922138711010162107879888888538848407132327215161696479014638246148780516059076502007170233816521638866237445955186196199106181664196333035350522256775772678749757516076687671733088043974750225859037634391059057871128952528114293385763258675546471992534732373945591487042489023109902330242980705545998552851661474245748466697559479508930710234503328250288511766352977719334252928597855882930620741923986586828547412389638821815758450532251881301327049927072714545264108360496728434366393519356711418047944068773770531352206244052618670493983767902201878934735288733850555036281883721724473","s":"66794590351311400173440340223561508784777853797981871904981559245334503567545616382611784848902543717386870008558289905316601662574754089209687052710438230437549560386636286514822680768065835610624750399055088116166226098175424830519537908801592274839622946402090491946787040058370552124732885892610142242847158959492000732292603755213902976259446731410240912872744210451254301242220759673686769861789834996124153811460984114732824978048021325148492655982695079333718710090836034672739682282204904856516947015563681443657793597047393731812247221167838278986153621564706820976058621996938916226023920421313258317181056","r":{"height":"37686658568948037814775431903843597441856100114754323955796133079330648476309192012260294209465266635551131504125646637359931844595436529982289207908218765877672222632310887737940054188921134584912244256324727048869497937750475441196124576035922245172355820888415660512858847440533214955712359488689065763607483137995713620001810321655685884305156101062519673602853819411046367019986397235673847881046529391589711229735614071805410066894389088951657447726215788267372471488185033424222037788505918934857840957649277458736101301203881379280675945440723899652144116975079241713669490809165909240425120649887001447597783","sex":"48901017446440182649799731593114947230876351500273905015595989118217119375071111218399500737051508041416910144890371937193478691958771514378058820388069120931504416289663010431000145369715463131882383259114210820041731832960312557792681552574471886139487662967612807830334835729846093444859302732007584479807271091676491277902271511164922767210557187133481955551837663018165430244652992048757580783775433571336475692686259720997931194126203237043117966211161878071070916577025579669942228991696500136399569383974985399786080235342264485395522119939857486145401501612186163491615961653478438596959371113747671419654818","master_secret":"25754344723836699563584283879786692153622691083042382144160949511089528018631287834606498465418239311334501386316618629687258527283908520406207259178795217648481719864528515688115872808761112818709464686844054961387398147908732686218740513751960844653382166618983380191016571483892249629309506399346596975262589381752411984820505602091163687287542251803844421163362364666975191601496467090517324300542321861313152630025880504086070664031524805153571288074723002683472372414034607393588926109015678216745625826790077479058525170476570603845174669212586627449339894597259739762350550126584394404404482135882343197379054","name":"64945144723199018124037264140277156942131666148001245998219662472757345342279533884405888431954009830746588251472121029944168008438815350643138701794229741155411122621890661138856631059298571458398258239896113210276837384872922411226059610000961503919325158321529528085516642820682380678880886510720705463915144189095545183388444662260696183777535832602518582169729325489244691039221691384084009024188000745680035168934609700642727769603625029893488551202843527601643121220149122355960460523112480070939364242895718918315978456710031746858656148388609050488969420517950113219916527876709626082332309036117494497571230","age":"32059832863983999153613274260157019698296212529496396734792926477728751870868732126531732944880026440901943732956875433636855727848522486073745001899386738358016223503298068118020520201025961660332519845724521320552467451946852925824035412812595344753770029091958417300642692814810865758776286263929051571009155820474717897179825570107678882180230319004359558595714472285100325554837250772201405847343231203624749918461130474867722155978675551762505078508248381791048831193422832357874770535478244636601382323151375446307087219224928662366021820679699538198192887109930714869161019271417169222414370495648047714662103"},"rctxt":"38527464755916130963069611882293312815641859720607042775748742527688895624917359948168832828223678535804570958646474457323858571801037955359525462917173252086033591899208879285429574561167189107147758287137082689831331351781369164690717667586513821072095969666206581907243540078811132148136508600170388059098530570400824663936962403223100603326027117401899329035603739144303108339956544437073624926208818126402005595194344120188160525632489014089138283290414616529527375527577666875823786710497945303252443476610222721607664991987281949777517734685590949741562190122640202895612444667451959072089271004850428610427341","z":"31160349078984317779569363785252606468286101126154161634595102825752576352018565401209247600497171866986884547654707390053445672860929599916189762737605262398652714436350679825010487409345252016639698884761154432723648619393558760904141612222413004613912305317054390982133492273484244661652402423836430130022761985374095739624351663212686292616011934960947889676162946869205272435766196882679460333258355511812361345778943009086137697548566706243827603133668933678120765799991107515465495261132740007129958253450651703438567276912235691326876396719017894799034243480316169679472944643292666194979984921170821328746189"}}}"#; + const CRED_DATA: &str = r#"{"ver":"1.0","id":"V4SGRU86Z58d6TV7PBUe6f:3:CL:17:oI6Iokv","schemaId":"17","type":"CL","tag":"oI6Iokv","value":{"primary":{"n":"87178281071734731437690387382922138711010162107879888888538848407132327215161696479014638246148780516059076502007170233816521638866237445955186196199106181664196333035350522256775772678749757516076687671733088043974750225859037634391059057871128952528114293385763258675546471992534732373945591487042489023109902330242980705545998552851661474245748466697559479508930710234503328250288511766352977719334252928597855882930620741923986586828547412389638821815758450532251881301327049927072714545264108360496728434366393519356711418047944068773770531352206244052618670493983767902201878934735288733850555036281883721724473","s":"66794590351311400173440340223561508784777853797981871904981559245334503567545616382611784848902543717386870008558289905316601662574754089209687052710438230437549560386636286514822680768065835610624750399055088116166226098175424830519537908801592274839622946402090491946787040058370552124732885892610142242847158959492000732292603755213902976259446731410240912872744210451254301242220759673686769861789834996124153811460984114732824978048021325148492655982695079333718710090836034672739682282204904856516947015563681443657793597047393731812247221167838278986153621564706820976058621996938916226023920421313258317181056","r":{"height":"37686658568948037814775431903843597441856100114754323955796133079330648476309192012260294209465266635551131504125646637359931844595436529982289207908218765877672222632310887737940054188921134584912244256324727048869497937750475441196124576035922245172355820888415660512858847440533214955712359488689065763607483137995713620001810321655685884305156101062519673602853819411046367019986397235673847881046529391589711229735614071805410066894389088951657447726215788267372471488185033424222037788505918934857840957649277458736101301203881379280675945440723899652144116975079241713669490809165909240425120649887001447597783","sex":"48901017446440182649799731593114947230876351500273905015595989118217119375071111218399500737051508041416910144890371937193478691958771514378058820388069120931504416289663010431000145369715463131882383259114210820041731832960312557792681552574471886139487662967612807830334835729846093444859302732007584479807271091676491277902271511164922767210557187133481955551837663018165430244652992048757580783775433571336475692686259720997931194126203237043117966211161878071070916577025579669942228991696500136399569383974985399786080235342264485395522119939857486145401501612186163491615961653478438596959371113747671419654818","master_secret":"25754344723836699563584283879786692153622691083042382144160949511089528018631287834606498465418239311334501386316618629687258527283908520406207259178795217648481719864528515688115872808761112818709464686844054961387398147908732686218740513751960844653382166618983380191016571483892249629309506399346596975262589381752411984820505602091163687287542251803844421163362364666975191601496467090517324300542321861313152630025880504086070664031524805153571288074723002683472372414034607393588926109015678216745625826790077479058525170476570603845174669212586627449339894597259739762350550126584394404404482135882343197379054","name":"64945144723199018124037264140277156942131666148001245998219662472757345342279533884405888431954009830746588251472121029944168008438815350643138701794229741155411122621890661138856631059298571458398258239896113210276837384872922411226059610000961503919325158321529528085516642820682380678880886510720705463915144189095545183388444662260696183777535832602518582169729325489244691039221691384084009024188000745680035168934609700642727769603625029893488551202843527601643121220149122355960460523112480070939364242895718918315978456710031746858656148388609050488969420517950113219916527876709626082332309036117494497571230","age":"32059832863983999153613274260157019698296212529496396734792926477728751870868732126531732944880026440901943732956875433636855727848522486073745001899386738358016223503298068118020520201025961660332519845724521320552467451946852925824035412812595344753770029091958417300642692814810865758776286263929051571009155820474717897179825570107678882180230319004359558595714472285100325554837250772201405847343231203624749918461130474867722155978675551762505078508248381791048831193422832357874770535478244636601382323151375446307087219224928662366021820679699538198192887109930714869161019271417169222414370495648047714662103"},"rctxt":"38527464755916130963069611882293312815641859720607042775748742527688895624917359948168832828223678535804570958646474457323858571801037955359525462917173252086033591899208879285429574561167189107147758287137082689831331351781369164690717667586513821072095969666206581907243540078811132148136508600170388059098530570400824663936962403223100603326027117401899329035603739144303108339956544437073624926208818126402005595194344120188160525632489014089138283290414616529527375527577666875823786710497945303252443476610222721607664991987281949777517734685590949741562190122640202895612444667451959072089271004850428610427341","z":"31160349078984317779569363785252606468286101126154161634595102825752576352018565401209247600497171866986884547654707390053445672860929599916189762737605262398652714436350679825010487409345252016639698884761154432723648619393558760904141612222413004613912305317054390982133492273484244661652402423836430130022761985374095739624351663212686292616011934960947889676162946869205272435766196882679460333258355511812361345778943009086137697548566706243827603133668933678120765799991107515465495261132740007129958253450651703438567276912235691326876396719017894799034243480316169679472944643292666194979984921170821328746189"}}}"#; #[test] - pub fn test_build_cred_def_request_success(){ + pub fn test_build_cred_def_request_success() { let wallet = Wallet::new(); let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); @@ -560,75 +563,75 @@ mod test_build_cred_def_request { } #[cfg(test)] -mod test_build_get_cred_def_request { - -} +mod test_build_get_cred_def_request {} #[cfg(test)] -mod test_build_node_request { - -} +mod test_build_node_request {} #[cfg(test)] -mod test_build_get_validator_info_request { - -} +mod test_build_get_validator_info_request {} #[cfg(test)] -mod test_build_pool_config_request { - -} +mod test_build_pool_config_request {} #[cfg(test)] -mod test_build_pool_restart_request { - -} +mod test_build_pool_restart_request {} #[cfg(test)] -mod test_build_pool_upgrade_request { - -} +mod test_build_pool_upgrade_request {} #[cfg(test)] -mod test_build_revoc_reg_def_request { - -} +mod test_build_revoc_reg_def_request {} #[cfg(test)] -mod test_build_get_revoc_reg_def_request { - -} +mod test_build_get_revoc_reg_def_request {} #[cfg(test)] -mod test_parse_get_revoc_reg_def_response { - -} +mod test_parse_get_revoc_reg_def_response {} #[cfg(test)] -mod test_build_revoc_reg_entry_request { -} +mod test_build_revoc_reg_entry_request {} #[cfg(test)] -mod test_build_get_revoc_reg_request { - -} +mod test_build_get_revoc_reg_request {} #[cfg(test)] -mod test_parse_get_revoc_reg_response { - -} +mod test_parse_get_revoc_reg_response {} #[cfg(test)] -mod test_build_get_revoc_reg_delta_request { - -} +mod test_build_get_revoc_reg_delta_request {} #[cfg(test)] -mod test_parse_get_revoc_reg_delta_response { +mod test_parse_get_revoc_reg_delta_response {} -} +#[cfg(test)] +mod test_register_transaction_parser_for_sp {} #[cfg(test)] -mod test_register_transaction_parser_for_sp { +mod test_build_auth_rule_request { + use super::*; -} + const DID: &str = "VsKV7grR1BUE29mG2Fm2kX"; + const NYM_AUTH_TYPE: &str = "1"; + const ADD_AUTH_ACTION: &str = "ADD"; + const FIELD: &str = "role"; + const NEW_VALUE: &str = "101"; + const ROLE_CONSTRAINT: &str = r#"{ + "sig_count": 1, + "metadata": {}, + "role": "0", + "constraint_id": "ROLE", + "need_to_be_owner": false + }"#; + + #[test] + pub fn build_auth_rule_request_success() { + let _nym_result = ledger::build_auth_rule_request(DID, + NYM_AUTH_TYPE, + &ADD_AUTH_ACTION, + FIELD, + None, + NEW_VALUE, + ROLE_CONSTRAINT).wait().unwrap(); + } +} \ No newline at end of file