diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ccfc01a06..388a637b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 1.8.3 - 2019-04-30 +* Bugfixes: + * Fixed behavior of `auth_rule` and `get_auth_rule` request builders. + * Extended windows packages to contain *.dll.lib file. + * Fixed `boolean` datatype representation for FFI. + * others minor bugfixes + ## 1.8.2 - 2019-03-26 * Added new functions to Libindy Ledger API: * `indy_build_auth_rule_request` to change an existing ledger auth rule. @@ -21,6 +28,7 @@ Added `protocol_type` field to VCX provisioning config with indicates A2A messag * [Message Threading](https://github.com/hyperledger/indy-hipe/tree/master/text/0027-message-id-and-threading) * [Wire Message](https://github.com/hyperledger/indy-hipe/tree/master/text/0028-wire-message-format). * Set default freshness threshold to 600 seconds. +* Send GET requests to two Nodes. * Bugfixes: * Restart catchup in case of outdated pool cache. * Fixed publishing of nodejs package for VCX wrapper. diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd index f40186efc6..d5e9c3d6c6 100644 --- a/Jenkinsfile.cd +++ b/Jenkinsfile.cd @@ -402,7 +402,7 @@ def linuxVcxBuild(file, env_name, network_name, stashBuildResults) { testEnv.inside("--network=${network_name}") { sh ''' cd vcx/dummy-cloud-agent - LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run sample-config.json & + LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run config/sample-config.json & ''' echo "${env_name} Libvcx Test: Run tests" @@ -415,8 +415,8 @@ def linuxVcxBuild(file, env_name, network_name, stashBuildResults) { testEnv.inside("--network=${network_name}") { sh ''' cd vcx/dummy-cloud-agent - sed -i 's/\\("protocol_type": "\\)1.0/\\12.0/' sample-config.json - LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run sample-config.json & + sed -i 's/\\("protocol_type": "\\)1.0/\\12.0/' config/sample-config.json + LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run config/sample-config.json & ''' echo "${env_name} Libvcx Test: Run vcx demo test for protocol version 2.0" @@ -590,7 +590,7 @@ def windowsTesting() { bat "cargo test --release" } } - stash includes: 'target/release/*.dll', name: 'LibindyWindowsBuildResult' + stash includes: 'target/release/*.dll,target/release/*.dll.lib', name: 'LibindyWindowsBuildResult' } dir('libnullpay') { @@ -612,7 +612,7 @@ def windowsTesting() { } } - stash includes: 'target/release/*.dll', name: 'LibnullpayWindowsBuildResult' + stash includes: 'target/release/*.dll,target/release/*.dll.lib', name: 'LibnullpayWindowsBuildResult' } bat "PowerShell.exe \"Copy-Item $WORKSPACE/libnullpay/target/release/nullpay.dll -Destination $WORKSPACE/cli\"" @@ -672,7 +672,7 @@ def windowsTesting() { } } - stash includes: 'target/release/*.dll', name: 'LibvcxWindowsBuildResult' + stash includes: 'target/release/*.dll,target/release/*.dll.lib', name: 'LibvcxWindowsBuildResult' } //TODO wrappers testing @@ -1386,24 +1386,21 @@ def publishLibnullpayDebRCtoStable(testEnv) { def publishLibvcxDebRCtoStable(testEnv) { def libvcxVersion = getSrcVersion("vcx/libvcx") - def libindyVersion = getSrcVersion("libindy") - def rcFullVersion = "$libvcxVersion~$env.BUILD_NUMBER" - - testEnv.inside { - unstash name: "libvcxDebs" - sh "fpm -s deb -t deb --version $rcFullVersion --no-auto-depends --depends 'libindy = $libindyVersion' -f -p vcx/libvcx/debs vcx/libvcx/debs/libvcx_\"$rcFullVersion\"_amd64.deb" - stash includes: "vcx/libvcx/debs/*", name: "libvcxDebs" - } publishDebRCtoStable(testEnv, "libvcx", "vcx/libvcx", libvcxVersion, "libvcxDebs", false) } def publishDebRCtoStable(testEnv, packageName, folder, version, stashName, moveDevArtifacts) { testEnv.inside { - rcFullVersion = "${version}~${env.BUILD_NUMBER}" + def rcFullVersion = "${version}~${env.BUILD_NUMBER}" unstash name: stashName + if (packageName != "libindy") { + def libindyVersion = getSrcVersion("libindy") + sh "fpm -s deb -t deb --version $rcFullVersion --no-auto-depends --depends 'libindy = $libindyVersion' -f -p $folder/debs $folder/debs/\"$packageName\"_\"$rcFullVersion\"_amd64.deb" + } + sh "fakeroot deb-reversion -v $version $folder/debs/\"$packageName\"_\"$rcFullVersion\"_amd64.deb" if (moveDevArtifacts) { diff --git a/Jenkinsfile.ci b/Jenkinsfile.ci index ca436d7547..270f7d573f 100644 --- a/Jenkinsfile.ci +++ b/Jenkinsfile.ci @@ -523,7 +523,7 @@ def linuxVcxBuild(file, env_name, network_name) { testEnv.inside("--network=${network_name}") { sh ''' cd vcx/dummy-cloud-agent - LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run sample-config.json & + LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run config/sample-config.json & ''' echo "${env_name} Libvcx Test: Run tests" @@ -536,8 +536,8 @@ def linuxVcxBuild(file, env_name, network_name) { testEnv.inside("--network=${network_name}") { sh ''' cd vcx/dummy-cloud-agent - sed -i 's/\\("protocol_type": "\\)1.0/\\12.0/' sample-config.json - LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run sample-config.json & + sed -i 's/\\("protocol_type": "\\)1.0/\\12.0/' config/sample-config.json + LIBRARY_PATH=./ LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} RUST_BACKTRACE=1 RUST_LOG=indy=info cargo run config/sample-config.json & ''' echo "${env_name} Libvcx Test: Run tests" diff --git a/Specs/libindy/1.8.1/libindy.podspec.json b/Specs/libindy/1.8.1/libindy.podspec.json index 5f8d052ee3..1407a75d01 100644 --- a/Specs/libindy/1.8.1/libindy.podspec.json +++ b/Specs/libindy/1.8.1/libindy.podspec.json @@ -15,7 +15,7 @@ "ios": "10.0" }, "source": { - "http": "https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.8.1.libindy.tar.gz" + "http": "https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.8.1/libindy.tar.gz" }, "source_files": "*.h", "vendored_libraries": "*.a", diff --git a/Specs/libindy/1.8.2/libindy.podspec.json b/Specs/libindy/1.8.2/libindy.podspec.json index 3f2a55d107..a27c56ef25 100644 --- a/Specs/libindy/1.8.2/libindy.podspec.json +++ b/Specs/libindy/1.8.2/libindy.podspec.json @@ -15,7 +15,7 @@ "ios": "10.0" }, "source": { - "http": "https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.8.2.libindy.tar.gz" + "http": "https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.8.2/libindy.tar.gz" }, "source_files": "*.h", "vendored_libraries": "*.a", diff --git a/Specs/libindy/1.8.3/libindy.podspec.json b/Specs/libindy/1.8.3/libindy.podspec.json new file mode 100644 index 0000000000..cf7343b76c --- /dev/null +++ b/Specs/libindy/1.8.3/libindy.podspec.json @@ -0,0 +1,23 @@ +{ + "name": "libindy", + "version": "1.8.3", + "summary": "Summary TODO.", + "description": "Description TODO.", + "homepage": "TODO", + "license": { + "type": "Apache License 2.0", + "file": "LICENSE" + }, + "authors": { + "Daniel Hardman": "daniel.hardman@evernym.com" + }, + "platforms": { + "ios": "10.0" + }, + "source": { + "http": "https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.8.3/libindy.tar.gz" + }, + "source_files": "*.h", + "vendored_libraries": "*.a", + "requires_arc": false +} diff --git a/ci/indy-pool.dockerfile b/ci/indy-pool.dockerfile index 4005784489..b55c5ac075 100644 --- a/ci/indy-pool.dockerfile +++ b/ci/indy-pool.dockerfile @@ -24,15 +24,13 @@ 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.726 -ARG indy_anoncreds_ver=1.0.32 -ARG indy_node_ver=1.6.862 +ARG indy_plenum_ver=1.7.0~dev766 +ARG indy_node_ver=1.7.0~dev896 ARG python3_indy_crypto_ver=0.4.5 ARG indy_crypto_ver=0.4.5 RUN apt-get update -y && apt-get install -y \ indy-plenum=${indy_plenum_ver} \ - indy-anoncreds=${indy_anoncreds_ver} \ indy-node=${indy_node_ver} \ python3-indy-crypto=${python3_indy_crypto_ver} \ libindy-crypto=${indy_crypto_ver} \ diff --git a/ci/ios-build.sh b/ci/ios-build.sh index b637ff254e..10cda8e9a1 100644 --- a/ci/ios-build.sh +++ b/ci/ios-build.sh @@ -14,6 +14,7 @@ package="$1" export PKG_CONFIG_ALLOW_CROSS=1 export POD_FILE_NAME=${package}.tar.gz +export LIBINDY_POD_VERSION=1.8.2 if [ -z "${OPENSSL_DIR}" ]; then export OPENSSL_DIR=/usr/local/Cellar/openssl/1.0.2q diff --git a/ci/win-zip-and-upload.sh b/ci/win-zip-and-upload.sh index 753e891000..d7c3d9b1a2 100644 --- a/ci/win-zip-and-upload.sh +++ b/ci/win-zip-and-upload.sh @@ -31,6 +31,7 @@ if [ ${package_type} = "lib" ] ; then mkdir ${TEMP_ARCH_DIR}/lib cp -r ${folder}/include ${TEMP_ARCH_DIR} cp ./target/release/*.dll ${TEMP_ARCH_DIR}/lib/ + cp ./target/release/*.dll.lib ${TEMP_ARCH_DIR}/lib/ elif [ ${package_type} = "executable" ] ; then cp ./target/release/*.dll ${TEMP_ARCH_DIR}/ cp ./target/release/${package}.exe ${TEMP_ARCH_DIR}/ diff --git a/cli/Cargo.lock b/cli/Cargo.lock index ac9b15e0eb..08427c369f 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -242,11 +242,11 @@ dependencies = [ [[package]] name = "indy" -version = "1.8.2" +version = "1.8.3" dependencies = [ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "indy-sys 1.8.2", + "indy-sys 1.8.3", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -259,13 +259,13 @@ dependencies = [ [[package]] name = "indy-cli" -version = "1.8.2" +version = "1.8.3" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "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)", - "indy 1.8.2", + "indy 1.8.3", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "indy-sys" -version = "1.8.2" +version = "1.8.3" dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index c46562da0a..2a3ebc59eb 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "indy-cli" -version = "1.8.2" +version = "1.8.3" authors = ["Vyacheslav Gudkov "] [features] @@ -28,4 +28,4 @@ serde_json = "1.0" serde_derive = "1.0" term = "0.4.6" rpassword = "1.0.0" -indy = { version = "1.8.2", path = "../wrappers/rust/" } +indy = { version = "1.8.3", path = "../wrappers/rust/" } diff --git a/cli/debian/changelog b/cli/debian/changelog index a53ec794a7..a9c8266c39 100644 --- a/cli/debian/changelog +++ b/cli/debian/changelog @@ -1,7 +1,10 @@ -indy-cli (1.8.2) unstable; urgency=medium +indy-cli (1.8.3) unstable; urgency=medium [ Hyperledger ] +## 1.8.3 +* Updated `ledger auth-rule` and `ledger get-auth-rule` commands. + ## 1.8.2 * Added new commands to work with ledger auth rules: * `ledger auth-rule` to change an existing. diff --git a/cli/src/commands/ledger.rs b/cli/src/commands/ledger.rs index 0f3b4b9bc5..e875b89e1a 100644 --- a/cli/src/commands/ledger.rs +++ b/cli/src/commands/ledger.rs @@ -90,7 +90,8 @@ pub mod nym_command { None, &mut vec![("dest", "Did"), ("verkey", "Verkey"), - ("role", "Role")]))?; + ("role", "Role")], + true))?; let receipts = parse_response_with_fees(&response_json, payment_method)?; @@ -143,7 +144,8 @@ pub mod get_nym_command { &[("identifier", "Identifier"), ("dest", "Dest"), ("verkey", "Verkey"), - ("role", "Role")])); + ("role", "Role")], + true)); trace!("execute << {:?}", res); res } @@ -204,7 +206,8 @@ pub mod attrib_command { .map(|result| print_transaction_response(result, "Attrib request has been sent to Ledger.", None, - &[attribute]))?; + &[attribute], + true))?; let receipts = parse_response_with_fees(&response_json, payment_method)?; @@ -259,7 +262,8 @@ pub mod get_attrib_command { .map(|result| print_transaction_response(result, "Following ATTRIB has been received.", None, - &[("data", "Data")])); + &[("data", "Data")], + true)); trace!("execute << {:?}", res); res } @@ -323,7 +327,8 @@ pub mod schema_command { Some("data"), &[("name", "Name"), ("version", "Version"), - ("attr_names", "Attributes")]))?; + ("attr_names", "Attributes")], + true))?; let receipts = parse_response_with_fees(&response_json, payment_method)?; @@ -450,7 +455,8 @@ pub mod get_schema_command { Some("data"), &[("name", "Name"), ("version", "Version"), - ("attr_names", "Attributes")])); + ("attr_names", "Attributes")], + true)); trace!("execute << {:?}", res); res } @@ -524,7 +530,8 @@ pub mod cred_def_command { "NodeConfig request has been sent to Ledger.", Some("data"), &[("primary", "Primary Key"), - ("revocation", "Revocation Key")]))?; + ("revocation", "Revocation Key")], + true))?; let receipts = parse_response_with_fees(&response_json, payment_method)?; @@ -578,7 +585,8 @@ pub mod get_cred_def_command { "Following Credential Definition has been received.", Some("data"), &[("primary", "Primary Key"), - ("revocation", "Revocation Key")])); + ("revocation", "Revocation Key")], + true)); trace!("execute << {:?}", res); res } @@ -652,7 +660,8 @@ pub mod node_command { ("client_port", "Client Port"), ("services", "Services"), ("blskey", "Blskey"), - ("blskey_pop", "Blskey Proof of Possession")])); + ("blskey_pop", "Blskey Proof of Possession")], + true)); trace!("execute << {:?}", res); res } @@ -691,7 +700,8 @@ pub mod pool_config_command { "NodeConfig request has been sent to Ledger.", None, &[("writes", "Writes"), - ("force", "Force Apply")])); + ("force", "Force Apply")], + true)); trace!("execute << {:?}", res); res } @@ -854,7 +864,8 @@ pub mod pool_upgrade_command { ("justification", "Justification"), ("reinstall", "Reinstall"), ("force", "Force Apply"), - ("package", "Package Name")])); + ("package", "Package Name")], + true)); if let Some(h) = hash { println_succ!("Hash:"); println!("{}", h); @@ -1226,7 +1237,7 @@ pub mod auth_rule_command { .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_optional_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. @@ -1257,7 +1268,7 @@ pub mod auth_rule_command { 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 new_value = get_opt_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) @@ -1283,7 +1294,8 @@ pub mod auth_rule_command { ("field", "Field"), ("old_value", "Old Value"), ("new_value", "New Value"), - ("constraint", "Constraint")]))?; + ("constraint", "Constraint")], + false))?; trace!("execute << {:?}", res); Ok(res) @@ -1339,13 +1351,21 @@ pub mod get_auth_rule_command { .iter() .map(|(constraint_id, constraint)| { let parts: Vec<&str> = constraint_id.split("--").collect(); + let auth_type = get_txn_title(&serde_json::Value::String(parts.get(0).cloned().unwrap_or("-").to_string())); + let action = parts.get(1); + let field = parts.get(2); + let old_value = match action { + Some(act) if *act == "ADD" => None, + _ => parts.get(3), + }; + let new_value = parts.get(4); json!({ - "auth_type": get_txn_title(&serde_json::Value::String(parts.get(1).cloned().unwrap_or("-").to_string())), - "auth_action": parts.get(0), - "field": parts.get(2), - "old_value": parts.get(3), - "new_value": parts.get(4), + "auth_type": auth_type, + "auth_action": action, + "field": field, + "old_value": old_value, + "new_value": new_value, "constraint": ::serde_json::to_string_pretty(&constraint).unwrap(), }) }) @@ -1476,7 +1496,8 @@ fn parse_payment_fees(fees: &Vec<&str>) -> Result { fn print_transaction_response(mut result: serde_json::Value, title: &str, data_sub_field: Option<&str>, - data_headers: &[(&str, &str)]) { + data_headers: &[(&str, &str)], + skip_empty: bool) { println_succ!("{}", title); let (metadata_headers, metadata, data) = match result["ver"].clone().as_str() { @@ -1490,7 +1511,9 @@ fn print_transaction_response(mut result: serde_json::Value, title: &str, let data = if data_sub_field.is_some() { &data[data_sub_field.unwrap()] } else { &data }; let mut data_headers = data_headers.to_vec(); - data_headers.retain(|&(ref key, _)| !data[key].is_null()); + if skip_empty { + data_headers.retain(|&(ref key, _)| !data[key].is_null()); + } println_succ!("Data:"); print_table(data, &data_headers); @@ -3663,16 +3686,33 @@ pub mod tests { }"#; #[test] - pub fn auth_rule_works() { + pub fn auth_rule_works_for_adding_new_trustee() { + 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", "0".to_string()); + params.insert("constraint", ROLE_CONSTRAINT.to_string()); + cmd.execute(&ctx, ¶ms).unwrap(); + } + tear_down_with_wallet_and_pool(&ctx); + } + + #[test] + pub fn auth_rule_works_for_demoting_trustee() { 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("action", "EDIT".to_string()); params.insert("field", "role".to_string()); - params.insert("new_value", "101".to_string()); + params.insert("old_value", "0".to_string()); params.insert("constraint", ROLE_CONSTRAINT.to_string()); cmd.execute(&ctx, ¶ms).unwrap(); } diff --git a/cli/src/libindy/ledger.rs b/cli/src/libindy/ledger.rs index 9280bb955d..035978e18f 100644 --- a/cli/src/libindy/ledger.rs +++ b/cli/src/libindy/ledger.rs @@ -86,7 +86,7 @@ impl Ledger { action: &str, field: &str, old_value: Option<&str>, - new_value: &str, + new_value: Option<&str>, constraint: &str, ) -> Result { ledger::build_auth_rule_request(submitter_did, txn_type, action, field, old_value, new_value, constraint).wait() diff --git a/docs/design/001-cli/README.md b/docs/design/001-cli/README.md index e756f37da1..c95dd440e2 100644 --- a/docs/design/001-cli/README.md +++ b/docs/design/001-cli/README.md @@ -336,7 +336,7 @@ 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}> +ledger auth-rule txn_type= action= field= [old_value=] [new_value=] constraint=<{constraint json}> ``` #### GET_AUTH_RULE transaction diff --git a/docs/how-tos/.gitignore b/docs/how-tos/.gitignore index 047420420c..0e5effc06e 100644 --- a/docs/how-tos/.gitignore +++ b/docs/how-tos/.gitignore @@ -1 +1,2 @@ -*/*/Cargo.lock \ No newline at end of file +*/*/Cargo.lock +__pycache__ \ No newline at end of file diff --git a/docs/how-tos/README.md b/docs/how-tos/README.md index 9f3e970d4f..5042c46652 100644 --- a/docs/how-tos/README.md +++ b/docs/how-tos/README.md @@ -1,5 +1,4 @@ # How Tos -* This folder contains short tutorials demonstrating how to accomplish common tasks with the Indy SDK. For best results, proceed through the following in order: diff --git a/docs/how-tos/issue-credential/README.md b/docs/how-tos/issue-credential/README.md index c011f9e501..8f0b28739f 100644 --- a/docs/how-tos/issue-credential/README.md +++ b/docs/how-tos/issue-credential/README.md @@ -4,9 +4,97 @@ After the ["Save Schema and Cred Def"](../save-schema-and-cred-def/README.md) how-to, an issuer is ready to do this workflow. When this how-to is finished, a logical next step might be ["Negotiate Proof"](../negotiate-proof/README.md) -[ [Java](java/README.md) | - [.NET](../not-yet-written.md) | - [Node.js](../not-yet-written.md) | - [Objective C](../not-yet-written.md) | - [Python](python/README.md) | - [Rust](rust/README.md)] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `issue_credential.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `issue_credential.py`, for nodejs: `issue_credential.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](java/template.java) | [Rust template](rust/src/template.rs)] + +This is a very simple app framework into which you'll plug the code +you'll be writing. + +### Step 2 + +This how-to builds on the work in ["Save Schema and Cred Def"](../save-schema-and-cred-def/README.md). +Rather than duplicate our explanation of those steps here, we will simply +copy that code as our starting point. + +Copy the contents of the correspondent *step2* file below into your `issue_credential` file +instead of the `Step 2 code goes here` placeholder comment, and save it. + +[ [Python step2](python/step2.py) | [Java step2](java/step2.java) | [Rust step2](rust/src/step2.rs)] + +### Step 3 + +So far, we have created an identity that can be used to issue credentials. +We need another one, now, that can be used to hold credentials once they're issued. + +Copy the contents of the correspondent *step3* file below into your `issue_credential` +file instead of the `Step 3 code goes here` placeholder comment. + +[ [Python step3](python/step3.py) | [Java step3](java/step3.java) | [Rust step3](rust/src/step3.rs)] + +Notice that this identity creates something called a *link secret* (formerly +called a *master secret*; this older term is now deprecated). +A link secret is a special piece of data that's inserted into +a credential, in blinded form, on issuance; it is used to prove that the +credential in question belongs to a particular holder and not to someone +else. Because Alice's credentials contain her link secret, only she can +use them. + +### Step 4 + +At this point, the issuer and the person who receives the credential +(called the *holder*) engage in an interactive protocol that results +in issuance. + +First, the issuer offers a credential. This step is optional; we include +it for completeness. Next, the holder requests the credential, supplying +the blinded link secret that will bind it to them. Finally, the issuer +generates the credential and gives it to the holder. + +![3-phase negotiation on issuance](3-phase-negotiation.png) + +These three steps embody a negotiation pattern that is used in many +indy interactions (e.g., in proving). Either party can begin; the other +party acknowledges and accepts--or makes a counter proposal. In the case +of a counter proposal, a new negotiation cycle begins; in the simpler +case, the negotiation is concluded successfully. Negotiation could be used +during credential issuance to negotiate a change to a credential (e.g., +to correct a typo or to ask an issuer to include or omit a piece of data +that they didn't initially propose); however, we don't cover that +advanced workflow here. + +One other note: the sample code in this step uses the word "claim" in +places where you might expect "credential." These used to be synonyms, +but usage has evolved in the W3C since the Indy SDK was built. "Credential" +is the newer word, and function and parameter names that refer to "claims" +are now deprecated. Eventually, all usage will show "credential." + +Copy the contents of *step4* file below into your `issue_credential` file instead of +the `Step 4 code goes here` placeholder comment and save it. + +[ [Python step4](python/step4.py) | [Java step4](java/step4.java) | [Rust step4](rust/src/step4.rs)] + +### Step 5 + +Run the completed demo and observe the whole sequence. + +[ [Python complete](python/issue_credential.py) | [Java complete](java/IssueCredential.java) | [Rust complete](rust/src/issue-credential.rs)] + +## More experiments + +You might try the ["Negotiate a Proof"](../negotiate-proof/README.md) +how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/issue-credential/java/README.md b/docs/how-tos/issue-credential/java/README.md deleted file mode 100644 index 44bead2cc9..0000000000 --- a/docs/how-tos/issue-credential/java/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# Issue a Credential -Indy-SDK Developer Walkthrough #4, Java Edition - -[ [.NET](../../not-yet-written.md) | - [Node.js](../../not-yet-written.md) | - [Objective C](../../not-yet-written.md) | - [Python](../python/README.md) | - [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine(VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a java editor of your -choice and paste the code from [template.java](template.java) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `IssueCredential.java`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Save Schema and Cred Def"](../save-schema-and-cred-def/../not-yet-written.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.java](step2.java) into -`IssueCredential.java` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.java`. - -### Step 3 - -So far, we have created an identity that can be used to issue credentials. -We need another one, now, that can be used to hold credentials once they're issued. - -Copy the contents of [step3.java](step3.java) into -`IssueCredential.java` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.java`. - -Notice that this identity creates something called a *link secret* (formerly -called a *master secret*; this older term is now deprecated). -A link secret is a special piece of data that's inserted into -a credential, in blinded form, on issuance; it is used to prove that the -credential in question belongs to a particular holder and not to someone -else. Because Alice's credentials contain her link secret, only she can -use them. - -### Step 4 - -At this point, the issuer and the person who receives the credential -(called the *holder*) engage in an interactive protocol that results -in issuance. - -First, the issuer offers a credential. This step is optional; we include -it for completeness. Next, the holder requests the credential, supplying -the blinded link secret that will bind it to them. Finally, the issuer -generates the credential and gives it to the holder. - -![3-phase negotiation on issuance](../3-phase-negotiation.png) - -These three steps embody a negotiation pattern that is used in many -indy interactions (e.g., in proving). Either party can begin; the other -party acknowledges and accepts--or makes a counter proposal. In the case -of a counter proposal, a new negotiation cycle begins; in the simpler -case, the negotiation is concluded successfully. Negotiation could be used -during credential issuance to negotiate a change to a credential (e.g., -to correct a typo or to ask an issuer to include or omit a piece of data -that they didn't initially propose); however, we don't cover that -advanced workflow here. - -One other note: the sample code in this step uses the word "claim" in -places where you might expect "credential." These used to be synonyms, -but usage has evolved in the W3C since the Indy SDK was built. "Credential" -is the newer word, and function and parameter names that refer to "claims" -are now deprecated. Eventually, all usage will show "credential." - -Copy the contents of [step4.java](step4.java) into -`IssueCredential.java` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.java`. - -### Step 5 - -Run the [finished code](IssueCredential.java) and observe the whole sequence. - -## More experiments - -You might try the ["Negotiate a Proof"](../../negotiate-proof/../not-yet-written.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/issue-credential/python/README.md b/docs/how-tos/issue-credential/python/README.md deleted file mode 100644 index 9a87d4376e..0000000000 --- a/docs/how-tos/issue-credential/python/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Issue a Credential -Indy-SDK Developer Walkthrough #4, Python Edition - -[ [Java](../java/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) - [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine(VM). See [prerequisites](../../prerequisites.md). -Ensure you have the 64-bit version of Python 3 installed, as the 32-bit version may have problems loading the Indy .dll files. - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a Python editor of your -choice and paste the code from [template.py](template.py) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `IssueCredential.py`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Save Schema and Cred Def"](../../save-schema-and-cred-def/python/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.py](step2.py) into -`IssueCredential.py` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.py`. - -### Step 3 - -So far, we have created an identity that can be used to issue credentials. -We need another one, now, that can be used to hold credentials once they're issued. - -Copy the contents of [step3.py](step3.py) into -`IssueCredential.py` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.py`. - -Notice that this identity creates something called a *link secret* (formerly -called a *master secret*; this older term is now deprecated). -A link secret is a special piece of data that's inserted into -a credential, in blinded form, on issuance; it is used to prove that the -credential in question belongs to a particular holder and not to someone -else. Because Alice's credentials contain her link secret, only she can -use them. - -### Step 4 - -At this point, the issuer and the person who receives the credential -(called the *holder*) engage in an interactive protocol that results -in issuance. - -First, the issuer offers a credential. This step is optional; we include -it for completeness. Next, the holder requests the credential, supplying -the blinded link secret that will bind it to them. Finally, the issuer -generates the credential and gives it to the holder. - -![3-phase negotiation on issuance](../3-phase-negotiation.png) - -These three steps embody a negotiation pattern that is used in many -indy interactions (e.g., in proving). Either party can begin; the other -party acknowledges and accepts--or makes a counter proposal. In the case -of a counter proposal, a new negotiation cycle begins; in the simpler -case, the negotiation is concluded successfully. Negotiation could be used -during credential issuance to negotiate a change to a credential (e.g., -to correct a typo or to ask an issuer to include or omit a piece of data -that they didn't initially propose); however, we don't cover that -advanced workflow here. - -One other note: the sample code in this step uses the word "claim" in -places where you might expect "credential." These used to be synonyms, -but usage has evolved in the W3C since the Indy SDK was built. "Credential" -is the newer word, and function and parameter names that refer to "claims" -are now deprecated. Eventually, all usage will show "credential." - -Copy the contents of [step4.py](step4.py) into -`IssueCredential.py` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `IssueCredential.py`. - -### Step 5 - -Run the [finished code](IssueCredential.py) and observe the whole sequence. - -## More experiments - -You might try the ["Negotiate a Proof"](../../negotiate-proof/python/README.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/issue-credential/python/issue_credential.py b/docs/how-tos/issue-credential/python/issue_credential.py index 4b2bbd8f8a..fbbfa950ff 100644 --- a/docs/how-tos/issue-credential/python/issue_credential.py +++ b/docs/how-tos/issue-credential/python/issue_credential.py @@ -12,21 +12,19 @@ Finally, Prover stores Credential in its wallet. """ - import asyncio import json import pprint from indy import pool, ledger, wallet, did, anoncreds -from indy.error import IndyError +from indy.error import ErrorCode, IndyError +from utils import open_wallet, get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' -wallet_config = json.dumps({"id": "wallet"}) -wallet_credentials = json.dumps({"key": "wallet_key"}) -PROTOCOL_VERSION=2 - +issuer_wallet_config = json.dumps({"id": "issuer_wallet"}) +issuer_wallet_credentials = json.dumps({"key": "issuer_wallet_key"}) +genesis_file_path = get_pool_genesis_txn_path(pool_name) def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -34,52 +32,44 @@ def print_log(value_color="", value_noncolor=""): ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - async def issue_credential(): try: - await pool.set_protocol_version(2) + await pool.set_protocol_version(PROTOCOL_VERSION) + # 1. - print_log('\n1. Creates a new local pool ledger configuration that is used ' + print_log('\n1. opening a new local pool ledger configuration that will be used ' 'later when connecting to ledger.\n') - pool_config = json.dumps({'genesis_txn': genesis_file_path}) + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) try: - await pool.create_pool_ledger_config(pool_name, pool_config) - except IndyError: - await pool.delete_pool_ledger_config(config_name=pool_name) - await pool.create_pool_ledger_config(pool_name, pool_config) + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. - print_log('\n2. Open pool ledger and get handle from libindy\n') + print_log('\n2. Open pool ledger and get the handle from libindy\n') pool_handle = await pool.open_pool_ledger(config_name=pool_name, config=None) # 3. - print_log('\n3. Creating new secure wallet\n') - try: - await wallet.create_wallet(wallet_config, wallet_credentials) - except IndyError: - await wallet.delete_wallet(wallet_config, wallet_credentials) - await wallet.create_wallet(wallet_config, wallet_credentials) + print_log('\n3. Creating Issuer wallet and opening it to get the handle.\n') + issuer_wallet_handle = await open_wallet(issuer_wallet_config, issuer_wallet_credentials) # 4. - print_log('\n4. Open wallet and get handle from libindy\n') - wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) - - # 5. - print_log('\n5. Generating and storing steward DID and verkey\n') + print_log('\n4. Generating and storing steward DID and verkey\n') steward_seed = '000000000000000000000000Steward1' did_json = json.dumps({'seed': steward_seed}) - steward_did, steward_verkey = await did.create_and_store_my_did(wallet_handle, did_json) + steward_did, steward_verkey = await did.create_and_store_my_did(issuer_wallet_handle, did_json) print_log('Steward DID: ', steward_did) print_log('Steward Verkey: ', steward_verkey) - # 6. - print_log('\n6. Generating and storing trust anchor DID and verkey\n') - trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(wallet_handle, "{}") + # 5. + print_log('\n5. Generating and storing trust anchor DID and verkey\n') + trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(issuer_wallet_handle, "{}") print_log('Trust anchor DID: ', trust_anchor_did) print_log('Trust anchor Verkey: ', trust_anchor_verkey) - # 7. - print_log('\n7. Building NYM request to add Trust Anchor to the ledger\n') + # 6. + print_log('\n6. Building NYM request to add Trust Anchor to the ledger\n') nym_transaction_request = await ledger.build_nym_request(submitter_did=steward_did, target_did=trust_anchor_did, ver_key=trust_anchor_verkey, @@ -88,106 +78,124 @@ async def issue_credential(): print_log('NYM transaction request: ') pprint.pprint(json.loads(nym_transaction_request)) - # 8. - print_log('\n8. Sending NYM request to the ledger\n') + # 7. + print_log('\n7. Sending NYM request to the ledger\n') nym_transaction_response = await ledger.sign_and_submit_request(pool_handle=pool_handle, - wallet_handle=wallet_handle, + wallet_handle=issuer_wallet_handle, submitter_did=steward_did, request_json=nym_transaction_request) print_log('NYM transaction response: ') pprint.pprint(json.loads(nym_transaction_response)) - # 9. - print_log('\n9. Build the SCHEMA request to add new schema to the ledger as a Steward\n') - seq_no = 1 + # 8. + print_log('\n8. Issuer create Credential Schema\n') schema = { - 'seqNo': seq_no, - 'dest': steward_did, - 'data': { - 'id': '1', - 'name': 'gvt', - 'version': '1.0', - 'ver': '1.0', - 'attrNames': ['age', 'sex', 'height', 'name'] - } + 'name': 'gvt', + 'version': '1.0', + 'attributes': '["age", "sex", "height", "name"]' } - schema_data = schema['data'] - print_log('Schema data: ') - pprint.pprint(schema_data) + issuer_schema_id, issuer_schema_json = await anoncreds.issuer_create_schema(steward_did, + schema['name'], + schema['version'], + schema['attributes']) print_log('Schema: ') - pprint.pprint(schema) - schema_request = await ledger.build_schema_request(steward_did, json.dumps(schema_data)) + pprint.pprint(issuer_schema_json) + + # 9. + print_log('\n9. Build the SCHEMA request to add new schema to the ledger\n') + schema_request = await ledger.build_schema_request(steward_did, issuer_schema_json) print_log('Schema request: ') pprint.pprint(json.loads(schema_request)) # 10. print_log('\n10. Sending the SCHEMA request to the ledger\n') - schema_response = await ledger.sign_and_submit_request(pool_handle, wallet_handle, steward_did, schema_request) + schema_response = \ + await ledger.sign_and_submit_request(pool_handle, + issuer_wallet_handle, + steward_did, + schema_request) print_log('Schema response:') pprint.pprint(json.loads(schema_response)) # 11. - print_log('\n11. Creating and storing CRED DEFINITION using anoncreds as Trust Anchor, for the given Schema\n') - cred_def_tag = 'cred_def_tag' + print_log('\n11. Creating and storing Credential Definition using anoncreds as Trust Anchor, for the given Schema\n') + cred_def_tag = 'TAG1' cred_def_type = 'CL' cred_def_config = json.dumps({"support_revocation": False}) - (cred_def_id, cred_def_json) = await anoncreds.issuer_create_and_store_credential_def(wallet_handle, trust_anchor_did, json.dumps(schema_data), - cred_def_tag, cred_def_type, cred_def_config) + (cred_def_id, cred_def_json) = \ + await anoncreds.issuer_create_and_store_credential_def(issuer_wallet_handle, + trust_anchor_did, + issuer_schema_json, + cred_def_tag, + cred_def_type, + cred_def_config) print_log('Credential definition: ') pprint.pprint(json.loads(cred_def_json)) # 12. - print_log('\n12. Creating Prover wallet and opening it to get the handle\n') + print_log('\n12. Creating Prover wallet and opening it to get the handle.\n') prover_did = 'VsKV7grR1BUE29mG2Fm2kX' prover_wallet_config = json.dumps({"id": "prover_wallet"}) prover_wallet_credentials = json.dumps({"key": "prover_wallet_key"}) - await wallet.create_wallet(prover_wallet_config, prover_wallet_credentials) - prover_wallet_handle = await wallet.open_wallet(prover_wallet_config, prover_wallet_credentials) + prover_wallet_handle = await open_wallet(prover_wallet_config, prover_wallet_credentials) # 13. - print_log('\n13. Prover is creating Master Secret\n') - master_secret_name = 'master_secret' - master_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, master_secret_name) + print_log('\n13. Prover is creating Link Secret\n') + prover_link_secret_name = 'link_secret' + link_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, + prover_link_secret_name) # 14. print_log('\n14. Issuer (Trust Anchor) is creating a Credential Offer for Prover\n') - schema_json = json.dumps(schema) - cred_offer_json = await anoncreds.issuer_create_credential_offer(wallet_handle, cred_def_id) + cred_offer_json = await anoncreds.issuer_create_credential_offer(issuer_wallet_handle, + cred_def_id) print_log('Credential Offer: ') pprint.pprint(json.loads(cred_offer_json)) # 15. print_log('\n15. Prover creates Credential Request for the given credential offer\n') - (cred_req_json, cred_req_metadata_json) = await anoncreds.prover_create_credential_req(prover_wallet_handle, prover_did, cred_offer_json, cred_def_json, master_secret_id) + (cred_req_json, cred_req_metadata_json) = \ + await anoncreds.prover_create_credential_req(prover_wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + prover_link_secret_name) print_log('Credential Request: ') pprint.pprint(json.loads(cred_req_json)) # 16. print_log('\n16. Issuer (Trust Anchor) creates Credential for Credential Request\n') cred_values_json = json.dumps({ - 'sex': ['male', '5944657099558967239210949258394887428692050081607692519917050011144233115103'], - 'name': ['Alex', '1139481716457488690172217916278103335'], - 'height': ['175', '175'], - 'age': ['28', '28'] + "sex": {"raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233"}, + "name": {"raw": "Alex", "encoded": "1139481716457488690172217916278103335"}, + "height": {"raw": "175", "encoded": "175"}, + "age": {"raw": "28", "encoded": "28"} }) - (cred_json, _, _) = await anoncreds.issuer_create_credential(wallet_handle, cred_offer_json, cred_req_json, cred_values_json, None, None) + (cred_json, _, _) = \ + await anoncreds.issuer_create_credential(issuer_wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, None, None) print_log('Credential: ') pprint.pprint(json.loads(cred_json)) # 17. - print_log('\n17. Prover processes and stores Credential\n') - await anoncreds.prover_store_credential(prover_wallet_handle, None, cred_req_metadata_json, cred_json, cred_def_json, None) + print_log('\n17. Prover processes and stores received Credential\n') + await anoncreds.prover_store_credential(prover_wallet_handle, None, + cred_req_metadata_json, + cred_json, + cred_def_json, None) # 18. print_log('\n18. Closing both wallet_handles and pool\n') - await wallet.close_wallet(wallet_handle) + await wallet.close_wallet(issuer_wallet_handle) await wallet.close_wallet(prover_wallet_handle) await pool.close_pool_ledger(pool_handle) # 19. print_log('\n19. Deleting created wallet_handles\n') - await wallet.delete_wallet(wallet_config, wallet_credentials) + await wallet.delete_wallet(issuer_wallet_config, issuer_wallet_credentials) await wallet.delete_wallet(prover_wallet_config, prover_wallet_credentials) # 20. diff --git a/docs/how-tos/issue-credential/python/step2.py b/docs/how-tos/issue-credential/python/step2.py index b66af6aa3b..16cfa80e1d 100644 --- a/docs/how-tos/issue-credential/python/step2.py +++ b/docs/how-tos/issue-credential/python/step2.py @@ -1,45 +1,37 @@ # 1. - print_log('\n1. Creates a new local pool ledger configuration that is used ' + print_log('\n1. opening a new local pool ledger configuration that will be used ' 'later when connecting to ledger.\n') - pool_config = json.dumps({'genesis_txn': genesis_file_path}) + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) try: - await pool.create_pool_ledger_config(pool_name, pool_config) - except IndyError: - await pool.delete_pool_ledger_config(config_name=pool_name) - await pool.create_pool_ledger_config(pool_name, pool_config) + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. - print_log('\n2. Open pool ledger and get handle from libindy\n') + print_log('\n2. Open pool ledger and get the handle from libindy\n') pool_handle = await pool.open_pool_ledger(config_name=pool_name, config=None) # 3. - print_log('\n3. Creating new secure wallet\n') - try: - await wallet.create_wallet(wallet_config, wallet_credentials) - except IndyError: - await wallet.delete_wallet(wallet_config, wallet_credentials) - await wallet.create_wallet(wallet_config, wallet_credentials) + print_log('\n3. Creating Issuer wallet and opening it to get the handle.\n') + issuer_wallet_handle = await open_wallet(issuer_wallet_config, issuer_wallet_credentials) # 4. - print_log('\n4. Open wallet and get handle from libindy\n') - wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) - - # 5. - print_log('\n5. Generating and storing steward DID and verkey\n') + print_log('\n4. Generating and storing steward DID and verkey\n') steward_seed = '000000000000000000000000Steward1' did_json = json.dumps({'seed': steward_seed}) - steward_did, steward_verkey = await did.create_and_store_my_did(wallet_handle, did_json) + steward_did, steward_verkey = await did.create_and_store_my_did(issuer_wallet_handle, did_json) print_log('Steward DID: ', steward_did) print_log('Steward Verkey: ', steward_verkey) - # 6. - print_log('\n6. Generating and storing trust anchor DID and verkey\n') - trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(wallet_handle, "{}") + # 5. + print_log('\n5. Generating and storing trust anchor DID and verkey\n') + trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(issuer_wallet_handle, "{}") print_log('Trust anchor DID: ', trust_anchor_did) print_log('Trust anchor Verkey: ', trust_anchor_verkey) - # 7. - print_log('\n7. Building NYM request to add Trust Anchor to the ledger\n') + # 6. + print_log('\n6. Building NYM request to add Trust Anchor to the ledger\n') nym_transaction_request = await ledger.build_nym_request(submitter_did=steward_did, target_did=trust_anchor_did, ver_key=trust_anchor_verkey, @@ -48,51 +40,57 @@ print_log('NYM transaction request: ') pprint.pprint(json.loads(nym_transaction_request)) - # 8. - print_log('\n8. Sending NYM request to the ledger\n') + # 7. + print_log('\n7. Sending NYM request to the ledger\n') nym_transaction_response = await ledger.sign_and_submit_request(pool_handle=pool_handle, - wallet_handle=wallet_handle, + wallet_handle=issuer_wallet_handle, submitter_did=steward_did, request_json=nym_transaction_request) print_log('NYM transaction response: ') pprint.pprint(json.loads(nym_transaction_response)) - # 9. - print_log('\n9. Build the SCHEMA request to add new schema to the ledger as a Steward\n') - seq_no = 1 + # 8. + print_log('\n8. Issuer create Credential Schema\n') schema = { - 'seqNo': seq_no, - 'dest': steward_did, - 'data': { - 'id': '1', - 'name': 'gvt', - 'version': '1.0', - 'ver': '1.0', - 'attrNames': ['age', 'sex', 'height', 'name'] - } + 'name': 'gvt', + 'version': '1.0', + 'attributes': '["age", "sex", "height", "name"]' } - schema_data = schema['data'] - print_log('Schema data: ') - pprint.pprint(schema_data) + issuer_schema_id, issuer_schema_json = await anoncreds.issuer_create_schema(steward_did, + schema['name'], + schema['version'], + schema['attributes']) print_log('Schema: ') - pprint.pprint(schema) - schema_request = await ledger.build_schema_request(steward_did, json.dumps(schema_data)) + pprint.pprint(issuer_schema_json) + + # 9. + print_log('\n9. Build the SCHEMA request to add new schema to the ledger\n') + schema_request = await ledger.build_schema_request(steward_did, issuer_schema_json) print_log('Schema request: ') pprint.pprint(json.loads(schema_request)) # 10. print_log('\n10. Sending the SCHEMA request to the ledger\n') - schema_response = await ledger.sign_and_submit_request(pool_handle, wallet_handle, steward_did, schema_request) + schema_response = \ + await ledger.sign_and_submit_request(pool_handle, + issuer_wallet_handle, + steward_did, + schema_request) print_log('Schema response:') pprint.pprint(json.loads(schema_response)) # 11. - print_log('\n11. Creating and storing CRED DEFINITION using anoncreds as Trust Anchor, for the given Schema\n') - cred_def_tag = 'cred_def_tag' + print_log('\n11. Creating and storing Credential Definition using anoncreds as Trust Anchor, for the given Schema\n') + cred_def_tag = 'TAG1' cred_def_type = 'CL' cred_def_config = json.dumps({"support_revocation": False}) - (cred_def_id, cred_def_json) = await anoncreds.issuer_create_and_store_credential_def(wallet_handle, trust_anchor_did, json.dumps(schema_data), - cred_def_tag, cred_def_type, cred_def_config) + (cred_def_id, cred_def_json) = \ + await anoncreds.issuer_create_and_store_credential_def(issuer_wallet_handle, + trust_anchor_did, + issuer_schema_json, + cred_def_tag, + cred_def_type, + cred_def_config) print_log('Credential definition: ') - pprint.pprint(json.loads(cred_def_json)) + pprint.pprint(json.loads(cred_def_json)) \ No newline at end of file diff --git a/docs/how-tos/issue-credential/python/step3.py b/docs/how-tos/issue-credential/python/step3.py index 6efe2bbe71..6341db70c7 100644 --- a/docs/how-tos/issue-credential/python/step3.py +++ b/docs/how-tos/issue-credential/python/step3.py @@ -1,12 +1,12 @@ # 12. - print_log('\n12. Creating Prover wallet and opening it to get the handle\n') + print_log('\n12. Creating Prover wallet and opening it to get the handle.\n') prover_did = 'VsKV7grR1BUE29mG2Fm2kX' prover_wallet_config = json.dumps({"id": "prover_wallet"}) prover_wallet_credentials = json.dumps({"key": "prover_wallet_key"}) - await wallet.create_wallet(prover_wallet_config, prover_wallet_credentials) - prover_wallet_handle = await wallet.open_wallet(prover_wallet_config, prover_wallet_credentials) + prover_wallet_handle = await open_wallet(prover_wallet_config, prover_wallet_credentials) # 13. - print_log('\n13. Prover is creating Master Secret\n') - master_secret_name = 'master_secret' - master_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, master_secret_name) + print_log('\n13. Prover is creating Link Secret\n') + prover_link_secret_name = 'link_secret' + link_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, + prover_link_secret_name) diff --git a/docs/how-tos/issue-credential/python/step4.py b/docs/how-tos/issue-credential/python/step4.py index b38bc1ebfe..c1b46134fd 100644 --- a/docs/how-tos/issue-credential/python/step4.py +++ b/docs/how-tos/issue-credential/python/step4.py @@ -1,43 +1,55 @@ # 14. print_log('\n14. Issuer (Trust Anchor) is creating a Credential Offer for Prover\n') - schema_json = json.dumps(schema) - cred_offer_json = await anoncreds.issuer_create_credential_offer(wallet_handle, cred_def_id) + cred_offer_json = await anoncreds.issuer_create_credential_offer(issuer_wallet_handle, + cred_def_id) print_log('Credential Offer: ') pprint.pprint(json.loads(cred_offer_json)) # 15. print_log('\n15. Prover creates Credential Request for the given credential offer\n') - (cred_req_json, cred_req_metadata_json) = await anoncreds.prover_create_credential_req(prover_wallet_handle, prover_did, cred_offer_json, cred_def_json, master_secret_id) + (cred_req_json, cred_req_metadata_json) = \ + await anoncreds.prover_create_credential_req(prover_wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + prover_link_secret_name) print_log('Credential Request: ') pprint.pprint(json.loads(cred_req_json)) # 16. print_log('\n16. Issuer (Trust Anchor) creates Credential for Credential Request\n') cred_values_json = json.dumps({ - 'sex': ['male', '5944657099558967239210949258394887428692050081607692519917050011144233115103'], - 'name': ['Alex', '1139481716457488690172217916278103335'], - 'height': ['175', '175'], - 'age': ['28', '28'] + "sex": {"raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233"}, + "name": {"raw": "Alex", "encoded": "1139481716457488690172217916278103335"}, + "height": {"raw": "175", "encoded": "175"}, + "age": {"raw": "28", "encoded": "28"} }) - (cred_json, _, _) = await anoncreds.issuer_create_credential(wallet_handle, cred_offer_json, cred_req_json, cred_values_json, None, None) + (cred_json, _, _) = \ + await anoncreds.issuer_create_credential(issuer_wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, None, None) print_log('Credential: ') pprint.pprint(json.loads(cred_json)) # 17. - print_log('\n17. Prover processes and stores Credential\n') - await anoncreds.prover_store_credential(prover_wallet_handle, None, cred_req_metadata_json, cred_json, cred_def_json, None) + print_log('\n17. Prover processes and stores received Credential\n') + await anoncreds.prover_store_credential(prover_wallet_handle, None, + cred_req_metadata_json, + cred_json, + cred_def_json, None) # 18. print_log('\n18. Closing both wallet_handles and pool\n') - await wallet.close_wallet(wallet_handle) + await wallet.close_wallet(issuer_wallet_handle) await wallet.close_wallet(prover_wallet_handle) await pool.close_pool_ledger(pool_handle) # 19. print_log('\n19. Deleting created wallet_handles\n') - await wallet.delete_wallet(wallet_config, wallet_credentials) + await wallet.delete_wallet(issuer_wallet_config, issuer_wallet_credentials) await wallet.delete_wallet(prover_wallet_config, prover_wallet_credentials) # 20. print_log('\n20. Deleting pool ledger config\n') - await pool.delete_pool_ledger_config(pool_name) + await pool.delete_pool_ledger_config(pool_name) \ No newline at end of file diff --git a/docs/how-tos/issue-credential/python/template.py b/docs/how-tos/issue-credential/python/template.py index 8335b58ac2..b522228176 100644 --- a/docs/how-tos/issue-credential/python/template.py +++ b/docs/how-tos/issue-credential/python/template.py @@ -1,32 +1,28 @@ """ -This sample is extensions of "write_schema_and_cred_def.py" +Example demonstrating Proof Verification. -Shows how to issue a credential as a Trust Anchor which has created a Cred Definition -for an existing Schema. +First Issuer creates Claim Definition for existing Schema. +After that, it issues a Claim to Prover (as in issue_credential.py example) -After Trust Anchor has successfully created and stored a Cred Definition using Anonymous Credentials, -Prover's wallet is created and opened, and used to generate Prover's Master Secret. -After that, Trust Anchor generates Credential Offer for given Cred Definition, using Prover's DID -Prover uses Credential Offer to create Credential Request -Trust Anchor then uses Prover's Credential Request to issue a Credential. -Finally, Prover stores Credential in its wallet. +Once Prover has successfully stored its Claim, it uses Proof Request that he +received, to get Claims which satisfy the Proof Request from his wallet. +Prover uses the output to create Proof, using its Master Secret. +After that, Proof is verified against the Proof Request """ - import asyncio import json import pprint from indy import pool, ledger, wallet, did, anoncreds -from indy.error import IndyError +from indy.error import ErrorCode, IndyError +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' -wallet_config = json.dumps({"id": "wallet"}) -wallet_credentials = json.dumps({"key": "wallet_key"}) -PROTOCOL_VERSION=2 - +issuer_wallet_config = json.dumps({"id": "issuer_wallet"}) +issuer_wallet_credentials = json.dumps({"key": "issuer_wallet_key"}) +genesis_file_path = get_pool_genesis_txn_path(pool_name) def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -34,25 +30,25 @@ def print_log(value_color="", value_noncolor=""): ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - -async def issue_credential(): +async def proof_negotiation(): try: - await pool.set_protocol_version(2) + await pool.set_protocol_version(PROTOCOL_VERSION) + # Step 2 code goes here. # Step 3 code goes here. # Step 4 code goes here. + # Step 5 code goes here. + except IndyError as e: print('Error occurred: %s' % e) - def main(): loop = asyncio.get_event_loop() - loop.run_until_complete(issue_credential()) + loop.run_until_complete(proof_negotiation()) loop.close() - if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/docs/how-tos/issue-credential/python/utils.py b/docs/how-tos/issue-credential/python/utils.py new file mode 100644 index 0000000000..a130d1b49c --- /dev/null +++ b/docs/how-tos/issue-credential/python/utils.py @@ -0,0 +1,43 @@ +from os import environ +from pathlib import Path +from tempfile import gettempdir + +from indy import wallet +from indy.error import ErrorCode, IndyError + +PROTOCOL_VERSION = 2 + +def get_pool_genesis_txn_path(pool_name): + path_temp = Path(gettempdir()).joinpath("indy") + path = path_temp.joinpath("{}.txn".format(pool_name)) + save_pool_genesis_txn_file(path) + return path + +def pool_genesis_txn_data(): + pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") + + return "\n".join([ + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( + pool_ip, pool_ip) + ]) + +def save_pool_genesis_txn_file(path): + data = pool_genesis_txn_data() + path.parent.mkdir(parents=True, exist_ok=True) + with open(str(path), "w+") as f: + f.writelines(data) + +# Open and create wallet if not exists +async def open_wallet(wallet_config, wallet_credentials): + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError as ex: + if ex.error_code == ErrorCode.WalletAlreadyExistsError: + pass + return await wallet.open_wallet(wallet_config, wallet_credentials) \ No newline at end of file diff --git a/docs/how-tos/issue-credential/rust/README.md b/docs/how-tos/issue-credential/rust/README.md deleted file mode 100644 index d0f8ca393f..0000000000 --- a/docs/how-tos/issue-credential/rust/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# Issue a Credential -Indy-SDK Developer Walkthrough #4, Rust Edition - -[ [.NET](../../not-yet-written.md) | - [Node.js](../../not-yet-written.md) | - [Objective C](../../not-yet-written.md) | - [Python](../python/README.md) | - [Java](../java/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine(VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a rust editor of your -choice and paste the code from [template.rs](template.rs) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `issue-credential.rs`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Save Schema and Cred Def"](../save-schema-and-cred-def/../not-yet-written.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.rs](step2.rs) into -`issue-credential.rs` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `issue-credential.rs`. - -### Step 3 - -So far, we have created an identity that can be used to issue credentials. -We need another one, now, that can be used to hold credentials once they're issued. - -Copy the contents of [step3.rs](step3.rs) into -`issue-credential.rs` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `issue-credential.rs`. - -Notice that this identity creates something called a *link secret* (formerly -called a *master secret*; this older term is now deprecated). -A link secret is a special piece of data that's inserted into -a credential, in blinded form, on issuance; it is used to prove that the -credential in question belongs to a particular holder and not to someone -else. Because Alice's credentials contain her link secret, only she can -use them. - -### Step 4 - -At this point, the issuer and the person who receives the credential -(called the *holder*) engage in an interactive protocol that results -in issuance. - -First, the issuer offers a credential. This step is optional; we include -it for completeness. Next, the holder requests the credential, supplying -the blinded link secret that will bind it to them. Finally, the issuer -generates the credential and gives it to the holder. - -![3-phase negotiation on issuance](../3-phase-negotiation.png) - -These three steps embody a negotiation pattern that is used in many -indy interactions (e.g., in proving). Either party can begin; the other -party acknowledges and accepts--or makes a counter proposal. In the case -of a counter proposal, a new negotiation cycle begins; in the simpler -case, the negotiation is concluded successfully. Negotiation could be used -during credential issuance to negotiate a change to a credential (e.g., -to correct a typo or to ask an issuer to include or omit a piece of data -that they didn't initially propose); however, we don't cover that -advanced workflow here. - -One other note: the sample code in this step uses the word "claim" in -places where you might expect "credential." These used to be synonyms, -but usage has evolved in the W3C since the Indy SDK was built. "Credential" -is the newer word, and function and parameter names that refer to "claims" -are now deprecated. Eventually, all usage will show "credential." - -Copy the contents of [step4.rs](step4.java) rs -`issue-credential.rs` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `issue-credential.rs`. - -### Step 5 - -Run the [finished code](issue-credential.rs) and observe the whole sequence. - -## More experiments - -You might try the ["Negotiate a Proof"](../../negotiate-proof/../not-yet-written.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/issue-credential/rust/src/issue-credential.rs b/docs/how-tos/issue-credential/rust/src/issue-credential.rs index 38c1dd79d5..6d8e9f9416 100644 --- a/docs/how-tos/issue-credential/rust/src/issue-credential.rs +++ b/docs/how-tos/issue-credential/rust/src/issue-credential.rs @@ -22,93 +22,93 @@ extern crate serde_json; // ------------------------------------------ // hyperledger crates // ------------------------------------------ -extern crate indy; // rust wrapper project +extern crate indyrs as indy; // rust wrapper project use std::env; use std::fs; use std::io::Write; use std::path::PathBuf; -use indy::did::Did; -use indy::anoncreds::Issuer; -use indy::ledger::Ledger; -use indy::pool::Pool; -use indy::anoncreds::Prover; -use indy::wallet::Wallet; +use indy::did; +use indy::future::Future; +use indy::ledger; +use indy::pool; +use indy::wallet; +use indy::anoncreds; const PROTOCOL_VERSION: usize = 2; static USEFUL_CREDENTIALS: &'static str = r#"{"key": "12345678901234567890123456789012"}"#; fn main() { - let wallet_name = "wallet"; - let pool_name = "pool"; + let wallet_name = "walletZZ"; + let pool_name = "poolZZ"; - indy::pool::Pool::set_protocol_version(PROTOCOL_VERSION).unwrap(); + indy::pool::set_protocol_version(PROTOCOL_VERSION).wait().unwrap(); println!("1. Creating a new local pool ledger configuration that can be used later to connect pool nodes"); let pool_config_file = create_genesis_txn_file_for_pool(pool_name); let pool_config = json!({ "genesis_txn" : &pool_config_file }); - Pool::create_ledger_config(&pool_name, Some(&pool_config.to_string())).unwrap(); + pool::create_pool_ledger_config(&pool_name, Some(&pool_config.to_string())).wait().unwrap(); println!("2. Open pool ledger and get the pool handle from libindy"); - let pool_handle: i32 = Pool::open_ledger(&pool_name, None).unwrap(); + let pool_handle: i32 = pool::open_pool_ledger(&pool_name, None).wait().unwrap(); println!("3. Creates a new wallet"); let config = json!({ "id" : wallet_name.to_string() }).to_string(); - Wallet::create(&config, USEFUL_CREDENTIALS).unwrap(); + wallet::create_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("4. Open wallet and get the wallet handle from libindy"); - let wallet_handle: i32 = Wallet::open(&config, USEFUL_CREDENTIALS).unwrap(); + let wallet_handle: i32 = wallet::open_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("5. Generating and storing steward DID and Verkey"); let first_json_seed = json!({ "seed":"000000000000000000000000Steward1" }).to_string(); - let (steward_did, _steward_verkey) = Did::new(wallet_handle, &first_json_seed).unwrap(); + let (steward_did, _steward_verkey) = did::create_and_store_my_did(wallet_handle, &first_json_seed).wait().unwrap(); println!("6. Generating and storing Trust Anchor DID and Verkey"); - let (trustee_did, trustee_verkey) = Did::new(wallet_handle, &"{}".to_string()).unwrap(); + let (trustee_did, trustee_verkey) = did::create_and_store_my_did(wallet_handle, &"{}".to_string()).wait().unwrap(); println!("7. Build NYM request to add Trust Anchor to the ledger"); - let build_nym_request: String = Ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).unwrap(); + let build_nym_request: String = ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).wait().unwrap(); println!("8. Sending the nym request to ledger"); - let _build_nym_sign_submit_result: String = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).unwrap(); + let _build_nym_sign_submit_result: String = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).wait().unwrap(); println!("9. Create Schema and Build the SCHEMA request to add new schema to the ledger as a Steward"); let name = "gvt"; let version = "1.0"; let attributes = r#"["age", "sex", "height", "name"]"#; - let (_schema_id, schema_json) = Issuer::create_schema(&steward_did, name, version, attributes).unwrap(); + let (_schema_id, schema_json) = anoncreds::issuer_create_schema(&steward_did, name, version, attributes).wait().unwrap(); - let build_schema_request: String = Ledger::build_schema_request(&steward_did, &schema_json).unwrap(); + let build_schema_request: String = ledger::build_schema_request(&steward_did, &schema_json).wait().unwrap(); println!("10. Sending the SCHEMA request to the ledger"); - let _signed_schema_request_response = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).unwrap(); + let _signed_schema_request_response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).wait().unwrap(); println!("11. Creating and storing CREDENTIAL DEFINITION using anoncreds as Trust Anchor, for the given Schema"); let config_json = r#"{ "support_revocation": false }"#; let tag = r#"TAG1"#; - let (cred_def_id, cred_def_json) = Issuer::create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).unwrap(); + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).wait().unwrap(); println!("12. Creating Prover wallet and opening it to get the handle"); let prover_did = "VsKV7grR1BUE29mG2Fm2kX"; let prover_wallet_name = "prover_wallet"; let prover_wallet_config = json!({ "id" : prover_wallet_name.to_string() }).to_string(); - Wallet::create(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); - let prover_wallet_handle: i32 = Wallet::open(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); + wallet::create_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); + let prover_wallet_handle: i32 = wallet::open_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); println!("13. Prover is creating Master Secret"); let master_secret_name = "master_secret"; - Prover::create_master_secret(prover_wallet_handle, Some(master_secret_name)).unwrap(); + anoncreds::prover_create_master_secret(prover_wallet_handle, Some(master_secret_name)).wait().unwrap(); println!("14. Issuer (Trust Anchor) is creating a Credential Offer for Prover"); - let cred_offer_json = Issuer::create_credential_offer(wallet_handle, &cred_def_id).unwrap(); + let cred_offer_json = anoncreds::issuer_create_credential_offer(wallet_handle, &cred_def_id).wait().unwrap(); println!("15. Prover creates Credential Request"); - let (cred_req_json, cred_req_metadata_json) = Prover::create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).unwrap(); + let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).wait().unwrap(); println!("16. Issuer (Trust Anchor) creates Credential for Credential Request"); @@ -122,23 +122,23 @@ fn main() { println!("cred_values_json = '{}'", &cred_values_json.to_string()); let (cred_json, _cred_revoc_id, _revoc_reg_delta_json) = - Issuer::create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).unwrap(); + anoncreds::issuer_create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).wait().unwrap(); println!("17. Prover processes and stores Credential"); - let out_cred_id = Prover::store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).unwrap(); + let out_cred_id = anoncreds::prover_store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).wait().unwrap(); println!("Stored Credential ID is {}", &out_cred_id); // Clean UP println!("17. Close and delete two wallets"); - Wallet::close(prover_wallet_handle).unwrap(); - Wallet::delete(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); - Wallet::close(wallet_handle).unwrap(); - Wallet::delete(&config, USEFUL_CREDENTIALS).unwrap(); + wallet::close_wallet(prover_wallet_handle).wait().unwrap(); + wallet::delete_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); + wallet::close_wallet(wallet_handle).wait().unwrap(); + wallet::delete_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("18. Close pool and delete pool ledger config"); - Pool::close(pool_handle).unwrap(); - Pool::delete(&pool_name).unwrap(); + pool::close_pool_ledger(pool_handle).wait().unwrap(); + pool::delete_pool_ledger(&pool_name).wait().unwrap(); } fn create_genesis_txn_file_for_pool(pool_name: &str) -> String { diff --git a/docs/how-tos/issue-credential/rust/src/step2.rs b/docs/how-tos/issue-credential/rust/src/step2.rs index 206a52025c..844f7cfa1d 100644 --- a/docs/how-tos/issue-credential/rust/src/step2.rs +++ b/docs/how-tos/issue-credential/rust/src/step2.rs @@ -1,50 +1,49 @@ -indy::pool::Pool::set_protocol_version(PROTOCOL_VERSION).unwrap(); +indy::pool::set_protocol_version(PROTOCOL_VERSION).wait().unwrap(); println!("1. Creating a new local pool ledger configuration that can be used later to connect pool nodes"); let pool_config_file = create_genesis_txn_file_for_pool(pool_name); let pool_config = json!({ - "genesis_txn" : &pool_config_file - }); -Pool::create_ledger_config(&pool_name, Some(&pool_config.to_string())).unwrap(); + "genesis_txn" : &pool_config_file +}); +pool::create_pool_ledger_config(&pool_name, Some(&pool_config.to_string())).wait().unwrap(); println!("2. Open pool ledger and get the pool handle from libindy"); -let pool_handle: i32 = Pool::open_ledger(&pool_name, None).unwrap(); +let pool_handle: i32 = pool::open_pool_ledger(&pool_name, None).wait().unwrap(); println!("3. Creates a new wallet"); let config = json!({ "id" : wallet_name.to_string() }).to_string(); -Wallet::create(&config, USEFUL_CREDENTIALS).unwrap(); +wallet::create_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("4. Open wallet and get the wallet handle from libindy"); -let wallet_handle: i32 = Wallet::open(&config, USEFUL_CREDENTIALS).unwrap(); +let wallet_handle: i32 = wallet::open_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("5. Generating and storing steward DID and Verkey"); let first_json_seed = json!({ -"seed":"000000000000000000000000Steward1" + "seed":"000000000000000000000000Steward1" }).to_string(); -let (steward_did, _steward_verkey) = Did::new(wallet_handle, &first_json_seed).unwrap(); +let (steward_did, _steward_verkey) = did::create_and_store_my_did(wallet_handle, &first_json_seed).wait().unwrap(); println!("6. Generating and storing Trust Anchor DID and Verkey"); -let (trustee_did, trustee_verkey) = Did::new(wallet_handle, &"{}".to_string()).unwrap(); +let (trustee_did, trustee_verkey) = did::create_and_store_my_did(wallet_handle, &"{}".to_string()).wait().unwrap(); println!("7. Build NYM request to add Trust Anchor to the ledger"); -let build_nym_request: String = Ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).unwrap(); +let build_nym_request: String = ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).wait().unwrap(); println!("8. Sending the nym request to ledger"); -let _build_nym_sign_submit_result: String = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).unwrap(); +let _build_nym_sign_submit_result: String = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).wait().unwrap(); println!("9. Create Schema and Build the SCHEMA request to add new schema to the ledger as a Steward"); let name = "gvt"; let version = "1.0"; let attributes = r#"["age", "sex", "height", "name"]"#; -let (_schema_id, schema_json) = Issuer::create_schema(&steward_did, name, version, attributes).unwrap(); +let (_schema_id, schema_json) = anoncreds::issuer_create_schema(&steward_did, name, version, attributes).wait().unwrap(); -let build_schema_request: String = Ledger::build_schema_request(&steward_did, &schema_json).unwrap(); +let build_schema_request: String = ledger::build_schema_request(&steward_did, &schema_json).wait().unwrap(); println!("10. Sending the SCHEMA request to the ledger"); -let _signed_schema_request_response = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).unwrap(); +let _signed_schema_request_response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).wait().unwrap(); println!("11. Creating and storing CREDENTIAL DEFINITION using anoncreds as Trust Anchor, for the given Schema"); let config_json = r#"{ "support_revocation": false }"#; let tag = r#"TAG1"#; - -let (cred_def_id, cred_def_json) = Issuer::create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).unwrap(); +let (cred_def_id, cred_def_json) = anoncreds::issuer_create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).wait().unwrap(); diff --git a/docs/how-tos/issue-credential/rust/src/step3.rs b/docs/how-tos/issue-credential/rust/src/step3.rs index 079282d3cb..a46c3b767c 100644 --- a/docs/how-tos/issue-credential/rust/src/step3.rs +++ b/docs/how-tos/issue-credential/rust/src/step3.rs @@ -2,9 +2,9 @@ println!("12. Creating Prover wallet and opening it to get the handle"); let prover_did = "VsKV7grR1BUE29mG2Fm2kX"; let prover_wallet_name = "prover_wallet"; let prover_wallet_config = json!({ "id" : prover_wallet_name.to_string() }).to_string(); -Wallet::create(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); -let prover_wallet_handle: i32 = Wallet::open(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); +wallet::create_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); +let prover_wallet_handle: i32 = wallet::open_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); println!("13. Prover is creating Master Secret"); let master_secret_name = "master_secret"; -Prover::create_master_secret(prover_wallet_handle, Some(master_secret_name)).unwrap(); +anoncreds::prover_create_master_secret(prover_wallet_handle, Some(master_secret_name)).wait().unwrap(); diff --git a/docs/how-tos/issue-credential/rust/src/step4.rs b/docs/how-tos/issue-credential/rust/src/step4.rs index a255ebd01f..37dd36ac11 100644 --- a/docs/how-tos/issue-credential/rust/src/step4.rs +++ b/docs/how-tos/issue-credential/rust/src/step4.rs @@ -1,35 +1,33 @@ println!("14. Issuer (Trust Anchor) is creating a Credential Offer for Prover"); -let cred_offer_json = Issuer::create_credential_offer(wallet_handle, &cred_def_id).unwrap(); +let cred_offer_json = anoncreds::issuer_create_credential_offer(wallet_handle, &cred_def_id).wait().unwrap(); println!("15. Prover creates Credential Request"); -let (cred_req_json, cred_req_metadata_json) = Prover::create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).unwrap(); +let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).wait().unwrap(); println!("16. Issuer (Trust Anchor) creates Credential for Credential Request"); - let cred_values_json = json!({ - "sex": { "raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103" }, - "name": { "raw": "Alex", "encoded": "99262857098057710338306967609588410025648622308394250666849665532448612202874" }, - "height": { "raw": "175", "encoded": "175" }, - "age": { "raw": "28", "encoded": "28" }, - }); + "sex": { "raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103" }, + "name": { "raw": "Alex", "encoded": "99262857098057710338306967609588410025648622308394250666849665532448612202874" }, + "height": { "raw": "175", "encoded": "175" }, + "age": { "raw": "28", "encoded": "28" }, +}); println!("cred_values_json = '{}'", &cred_values_json.to_string()); - let (cred_json, _cred_revoc_id, _revoc_reg_delta_json) = -Issuer::create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).unwrap(); + anoncreds::issuer_create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).wait().unwrap(); println!("17. Prover processes and stores Credential"); -let out_cred_id = Prover::store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).unwrap(); +let out_cred_id = anoncreds::prover_store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).wait().unwrap(); println!("Stored Credential ID is {}", &out_cred_id); // Clean UP println!("17. Close and delete two wallets"); -Wallet::close(prover_wallet_handle).unwrap(); -Wallet::delete(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); -Wallet::close(wallet_handle).unwrap(); -Wallet::delete(&config, USEFUL_CREDENTIALS).unwrap(); +wallet::close_wallet(prover_wallet_handle).wait().unwrap(); +wallet::delete_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); +wallet::close_wallet(wallet_handle).wait().unwrap(); +wallet::delete_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("18. Close pool and delete pool ledger config"); -Pool::close(pool_handle).unwrap(); -Pool::delete(&pool_name).unwrap(); \ No newline at end of file +pool::close_pool_ledger(pool_handle).wait().unwrap(); +pool::delete_pool_ledger(&pool_name).wait().unwrap(); diff --git a/docs/how-tos/issue-credential/rust/src/template.rs b/docs/how-tos/issue-credential/rust/src/template.rs index 24859bbfdf..de1dcecaf3 100644 --- a/docs/how-tos/issue-credential/rust/src/template.rs +++ b/docs/how-tos/issue-credential/rust/src/template.rs @@ -22,19 +22,19 @@ extern crate serde_json; // ------------------------------------------ // hyperledger crates // ------------------------------------------ -extern crate indy; // rust wrapper project +extern crate indyrs as indy; // rust wrapper project use std::env; use std::fs; use std::io::Write; use std::path::PathBuf; -use indy::did::Did; -use indy::ledger::Ledger; -use indy::pool::Pool; -use indy::wallet::Wallet; -use indy::anoncreds::Issuer; -use indy::anoncreds::Prover; +use indy::did; +use indy::future::Future; +use indy::ledger; +use indy::pool; +use indy::wallet; +use indy::anoncreds; const PROTOCOL_VERSION: usize = 2; static USEFUL_CREDENTIALS: &'static str = r#"{"key": "12345678901234567890123456789012"}"#; diff --git a/docs/how-tos/negotiate-proof/README.md b/docs/how-tos/negotiate-proof/README.md index 185d3e11db..4007ff59f0 100644 --- a/docs/how-tos/negotiate-proof/README.md +++ b/docs/how-tos/negotiate-proof/README.md @@ -5,9 +5,96 @@ and ["Issue Credential"](../issue-credential/README.md) how-tos, you have all the context for a credential holder and a relying party (verifier) to generate a zero-knowledge proof based on the credential. -[ [Python](python/README.md) | - [Rust](rust/README.md) - [Java](../not-yet-written.md) | - [.NET](../not-yet-written.md) | - [Node.js](nodejs/README.md) | - [Objective C](../not-yet-written.md) ] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `negotiate_proof.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `negotiate_proof.py`, for nodejs: `negotiate_proof.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](java/README.md) | [Node.js template](nodejs/template.js) | [Rust template](rust/src/template.rs)] + +This is a very simple app framework into which you'll plug the code +you'll be writing. + +### Step 2 + +This how-to builds on the work in ["Issue Credential"](../issue-credential/README.md). +Rather than duplicate our explanation of those steps here, we will simply +copy that code as our starting point. + +Copy the contents of the correspondent *step2* file below into your `negotiate_proof` file +instead of the `Step 2 code goes here` placeholder comment, and save it. + +[ [Python step2](python/step2.py) | [Node.js step2](nodejs/step2.js) | [Rust step2](rust/src/step2.rs)] + +### Step 3 + +Proof negotiation typically begins when a *verifier* (also called a *relying party*) +requests proof. (As with credential issuance, the process has three logical +phases, but it is rare to begin with a proof offer. However, if an initial +proof request is met with a counter-offer, the offering phase of the +sequence becomes relevant.) + +![3 phases of proof negotiation; first phase is uncommon](3-phases.png) + +A proof request is a JSON file that describes what sort of +proof would satisfy the relying party. + +Once the proof request is received, a holder of credentials must scan their +*identity wallet* to find out which credentials could be used to satisfy +the request. (Wallet scanning is inefficient, but this does not cause +problems for dozens or hundreds of credentials. At higher scale, a new +mechanism is needed. +[Work is underway](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g31e3a419cd_0_67) +to add index-driven search to indy wallets. Visit +[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) +to learn more.) + +Copy the contents of the correspondent *step3* file below into your `negotiate_proof` +file instead of the `Step 3 code goes here` placeholder comment. + +[ [Python step3](python/step3.py) | [Node.js step3](nodejs/step3.js) | [Rust step3](rust/src/step3.rs)] + +### Step 4 + +At this point, the holder becomes a *prover* by generating and presenting +a proof. This is done by building some JSON that selects the credentials +(out of those identified as valid candidates in the previous step), +that the prover wishes to use to satisfy the request. The prover calls +`prover_create_proof` function with appropriate parameters, and the +proof is created. + +Copy the contents of *step4* file below into your `negotiate_proof` file instead of +the `Step 4 code goes here` placeholder comment and save it. + +[ [Python step4](python/step4.py) | [Node.js step4](nodejs/step4.js) | [Rust step4](rust/src/step4.rs)] + +### Step 5 + +Finally, the verifier needs to check to be sure the proof that's presented +satisfies their criteria. This is easy; just call `verifier_verify_proof` function. + +Copy the contents of *step5* file below into `negotiate_proof` file instead of +the `Step 5 code goes here` placeholder comment and save it. + +[ [Python step5](python/step5.py) | [Node.js step5](nodejs/step5.js) | [Rust step5](rust/src/step5.rs)] + +### Step 6 + +Run the completed demo and observe the whole sequence. + +[ [Python complete](python/negotiate_proof.py) | [Node.js complete](nodejs/negotiateProof.js) | [Rust complete](rust/src/negotiate-proof.rs)] + +## More experiments + +You might try the ["Send a Secure Message"](../send-secure-msg/README.md) how-to. diff --git a/docs/how-tos/negotiate-proof/java/README.md b/docs/how-tos/negotiate-proof/java/README.md index 7edf93a2fb..417faf90c8 100644 --- a/docs/how-tos/negotiate-proof/java/README.md +++ b/docs/how-tos/negotiate-proof/java/README.md @@ -4,5 +4,5 @@ directory `how-tos/proof-negotiation` and was renamed to other languages in the directory `negotiate-proof`. But this Java script was not tested or validated, and all the `java` -directory must be completed (by a Java developper) (with `steps` and other) +directory must be completed (by a Java developer) (with `steps` and other) like for other "how-tos" scripts. diff --git a/docs/how-tos/negotiate-proof/nodejs/README.md b/docs/how-tos/negotiate-proof/nodejs/README.md deleted file mode 100644 index d4d2db4a19..0000000000 --- a/docs/how-tos/negotiate-proof/nodejs/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Negotiate a Proof - -Indy-SDK Developer Walkthrough #5, NodeJS Edition - -[ [Python](../python/README.md) | [Rust](../rust/README.md) | [Java](../../not-yet-written.md) | [.NET](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) ] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a python editor of your -choice and paste the code from [template.js](template.js) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `negotiateProof.js`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Issue Credential"](../../issue-credential/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.js](step2.js) into -`negotiateProof.js` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `negotiateProof.js`. - -### Step 3 - -Proof negotiation typically begins when a *verifier* (also called a *relying party*) -requests proof. (As with credential issuance, the process has three logical -phases, but it is rare to begin with a proof offer. However, if an initial -proof request is met with a counter-offer, the offering phase of the -sequence becomes relevant.) - -![3 phases of proof negotiation; first phase is uncommon](../3-phases.png) - -A proof request is a JSON file that describes what sort of -proof would satisfy the relying party. - -Once the proof request is received, a holder of credentials must scan their -*identity wallet* to find out which credentials could be used to satisfy -the request. (Wallet scanning is inefficient, but this does not cause -problems for dozens or hundreds of credentials. At higher scale, a new -mechanism is needed. -[Work is underway](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g31e3a419cd_0_67) -to add index-driven search to indy wallets. Visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) -to learn more.) - -Copy the contents of [step3.js](step3.js) into -`negotiateProof.js` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `negotiateProof.js`. - -### Step 4 - -At this point, the holder becomes a *prover* by generating and presenting -a proof. This is done by building some JSON that selects the credentials -(out of those identified as valid candidates in the previous step), -that the prover wishes to use to satisfy the request. The prover calls -`indy.proverCreateProof()` with appropriate parameters, and the -proof is created. - -Copy the contents of [step4.js](step4.js) into -`negotiateProof.js` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `negotiateProof.js`. - -### Step 6 - -Finally, the verifier needs to check to be sure the proof that's presented -satisfies their criteria. This is easy; just call `indy.verifierVerifyProof()`. - -Copy the contents of [step5.js](step5.js) into -`negotiateProof.js` on top of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `negotiateProof.js`. - -### Step 6 - -Run the [finished code](negotiateProof.js) and observe the whole sequence. - -## More experiments - -You might try the ["Send a Secure Message"](../../send-secure-msg/../not-yet-written.md) -how-to. diff --git a/docs/how-tos/negotiate-proof/nodejs/package.json b/docs/how-tos/negotiate-proof/nodejs/package.json index 7ea2859b87..5aea17f652 100644 --- a/docs/how-tos/negotiate-proof/nodejs/package.json +++ b/docs/how-tos/negotiate-proof/nodejs/package.json @@ -3,9 +3,9 @@ "version": "1.0.0", "private": true, "description": "Demonstrates using NodeJS wrapper for LibIndy through creating and retrieving DIDs", - "main": "writeDidAndQueryVerkey.js", + "main": "negotiateProof.js", "scripts": { - "start": "node writeDidAndQueryVerkey.js", + "start": "node negotiateProof.js", "ledger:start": "cd ../../../../ && docker build -f ci/indy-pool.dockerfile -t indy_pool . && docker run --name indy_pool -itd -p 9701-9708:9701-9708 indy_pool", "ledger:stop": "docker stop indy_pool && docker rm indy_pool" }, diff --git a/docs/how-tos/negotiate-proof/python/README.md b/docs/how-tos/negotiate-proof/python/README.md deleted file mode 100644 index ee3e10127e..0000000000 --- a/docs/how-tos/negotiate-proof/python/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Negotiate a Proof - -Indy-SDK Developer Walkthrough #5, Python Edition - -[ [Rust](../rust/README.md) | [Java](../../not-yet-written.md) | [.NET](../../not-yet-written.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) ] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a python editor of your -choice and paste the code from [template.py](template.py) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `negotiate_proof.py`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Issue Credential"](../issue-credential/../not-yet-written.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.py](step2.py) into -`negotiate_proof.py` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `negotiate_proof.py`. - -### Step 3 - -Proof negotiation typically begins when a *verifier* (also called a *relying party*) -requests proof. (As with credential issuance, the process has three logical -phases, but it is rare to begin with a proof offer. However, if an initial -proof request is met with a counter-offer, the offering phase of the -sequence becomes relevant.) - -![3 phases of proof negotiation; first phase is uncommon](../3-phases.png) - -A proof request is a JSON file that describes what sort of -proof would satisfy the relying party. - -Once the proof request is received, a holder of credentials must scan their -*identity wallet* to find out which credentials could be used to satisfy -the request. (Wallet scanning is inefficient, but this does not cause -problems for dozens or hundreds of credentials. At higher scale, a new -mechanism is needed. -[Work is underway](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g31e3a419cd_0_67) -to add index-driven search to indy wallets. Visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) -to learn more.) - -Copy the contents of [step3.py](step3.py) into -`negotiate_proof.py` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `negotiate_proof.py`. - -### Step 4 - -At this point, the holder becomes a *prover* by generating and presenting -a proof. This is done by building some JSON that selects the credentials -(out of those identified as valid candidates in the previous step), -that the prover wishes to use to satisfy the request. The prover calls -`anoncreds.prover_create_proof()` with appropriate parameters, and the -proof is created. - -Copy the contents of [step4.py](step4.py) into -`negotiate_proof.py` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `negotiate_proof.py`. - -### Step 6 - -Finally, the verifier needs to check to be sure the proof that's presented -satisfies their criteria. This is easy; just call `anoncreds.verifier_verify_proof()`. - -Copy the contents of [step5.py](step5.py) into -`negotiate_proof.py` on top of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `negotiate_proof.py`. - -### Step 6 - -Run the [finished code](negotiate_proof.py) and observe the whole sequence. - -## More experiments - -You might try the ["Send a Secure Message"](../../send-secure-msg/../not-yet-written.md) -how-to. diff --git a/docs/how-tos/negotiate-proof/python/negotiate_proof.py b/docs/how-tos/negotiate-proof/python/negotiate_proof.py new file mode 100644 index 0000000000..9a99d55bcf --- /dev/null +++ b/docs/how-tos/negotiate-proof/python/negotiate_proof.py @@ -0,0 +1,302 @@ +""" +Example demonstrating Proof Verification. + +First Issuer creates Claim Definition for existing Schema. +After that, it issues a Claim to Prover (as in issue_credential.py example) + +Once Prover has successfully stored its Claim, it uses Proof Request that he +received, to get Claims which satisfy the Proof Request from his wallet. +Prover uses the output to create Proof, using its Master Secret. +After that, Proof is verified against the Proof Request +""" + +import asyncio +import json +import pprint + +from indy import pool, ledger, wallet, did, anoncreds +from indy.error import ErrorCode, IndyError + +from utils import open_wallet, get_pool_genesis_txn_path, PROTOCOL_VERSION + +pool_name = 'pool' +issuer_wallet_config = json.dumps({"id": "issuer_wallet"}) +issuer_wallet_credentials = json.dumps({"key": "issuer_wallet_key"}) +genesis_file_path = get_pool_genesis_txn_path(pool_name) + +def print_log(value_color="", value_noncolor=""): + """set the colors for text.""" + HEADER = '\033[92m' + ENDC = '\033[0m' + print(HEADER + value_color + ENDC + str(value_noncolor)) + +async def proof_negotiation(): + try: + await pool.set_protocol_version(PROTOCOL_VERSION) + + # 1. + print_log('\n1. opening a new local pool ledger configuration that will be used ' + 'later when connecting to ledger.\n') + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) + try: + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass + + # 2. + print_log('\n2. Open pool ledger and get the handle from libindy\n') + pool_handle = await pool.open_pool_ledger(config_name=pool_name, config=None) + + # 3. + print_log('\n3. Creating Issuer wallet and opening it to get the handle.\n') + issuer_wallet_handle = await open_wallet(issuer_wallet_config, issuer_wallet_credentials) + + # 4. + print_log('\n4. Generating and storing steward DID and verkey\n') + steward_seed = '000000000000000000000000Steward1' + did_json = json.dumps({'seed': steward_seed}) + steward_did, steward_verkey = await did.create_and_store_my_did(issuer_wallet_handle, did_json) + print_log('Steward DID: ', steward_did) + print_log('Steward Verkey: ', steward_verkey) + + # 5. + print_log('\n5. Generating and storing trust anchor DID and verkey\n') + trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(issuer_wallet_handle, "{}") + print_log('Trust anchor DID: ', trust_anchor_did) + print_log('Trust anchor Verkey: ', trust_anchor_verkey) + + # 6. + print_log('\n6. Building NYM request to add Trust Anchor to the ledger\n') + nym_transaction_request = await ledger.build_nym_request(submitter_did=steward_did, + target_did=trust_anchor_did, + ver_key=trust_anchor_verkey, + alias=None, + role='TRUST_ANCHOR') + print_log('NYM transaction request: ') + pprint.pprint(json.loads(nym_transaction_request)) + + # 7. + print_log('\n7. Sending NYM request to the ledger\n') + nym_transaction_response = await ledger.sign_and_submit_request(pool_handle=pool_handle, + wallet_handle=issuer_wallet_handle, + submitter_did=steward_did, + request_json=nym_transaction_request) + print_log('NYM transaction response: ') + pprint.pprint(json.loads(nym_transaction_response)) + + # 8. + print_log('\n8. Issuer create Credential Schema\n') + schema = { + 'name': 'gvt', + 'version': '1.0', + 'attributes': '["age", "sex", "height", "name"]' + } + issuer_schema_id, issuer_schema_json = await anoncreds.issuer_create_schema(steward_did, + schema['name'], + schema['version'], + schema['attributes']) + print_log('Schema: ') + pprint.pprint(issuer_schema_json) + + # 9. + print_log('\n9. Build the SCHEMA request to add new schema to the ledger\n') + schema_request = await ledger.build_schema_request(steward_did, issuer_schema_json) + print_log('Schema request: ') + pprint.pprint(json.loads(schema_request)) + + # 10. + print_log('\n10. Sending the SCHEMA request to the ledger\n') + schema_response = \ + await ledger.sign_and_submit_request(pool_handle, + issuer_wallet_handle, + steward_did, + schema_request) + print_log('Schema response:') + pprint.pprint(json.loads(schema_response)) + + # 11. + print_log('\n11. Creating and storing Credential Definition using anoncreds as Trust Anchor, for the given Schema\n') + cred_def_tag = 'TAG1' + cred_def_type = 'CL' + cred_def_config = json.dumps({"support_revocation": False}) + + (cred_def_id, cred_def_json) = \ + await anoncreds.issuer_create_and_store_credential_def(issuer_wallet_handle, + trust_anchor_did, + issuer_schema_json, + cred_def_tag, + cred_def_type, + cred_def_config) + print_log('Credential definition: ') + pprint.pprint(json.loads(cred_def_json)) + + # 12. + print_log('\n12. Creating Prover wallet and opening it to get the handle.\n') + prover_did = 'VsKV7grR1BUE29mG2Fm2kX' + prover_wallet_config = json.dumps({"id": "prover_wallet"}) + prover_wallet_credentials = json.dumps({"key": "prover_wallet_key"}) + prover_wallet_handle = await open_wallet(prover_wallet_config, prover_wallet_credentials) + + # 13. + print_log('\n13. Prover is creating Link Secret\n') + prover_link_secret_name = 'link_secret' + link_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, + prover_link_secret_name) + + # 14. + print_log('\n14. Issuer (Trust Anchor) is creating a Credential Offer for Prover\n') + cred_offer_json = await anoncreds.issuer_create_credential_offer(issuer_wallet_handle, + cred_def_id) + print_log('Credential Offer: ') + pprint.pprint(json.loads(cred_offer_json)) + + # 15. + print_log('\n15. Prover creates Credential Request for the given credential offer\n') + (cred_req_json, cred_req_metadata_json) = \ + await anoncreds.prover_create_credential_req(prover_wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + prover_link_secret_name) + print_log('Credential Request: ') + pprint.pprint(json.loads(cred_req_json)) + + # 16. + print_log('\n16. Issuer (Trust Anchor) creates Credential for Credential Request\n') + cred_values_json = json.dumps({ + "sex": {"raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233"}, + "name": {"raw": "Alex", "encoded": "1139481716457488690172217916278103335"}, + "height": {"raw": "175", "encoded": "175"}, + "age": {"raw": "28", "encoded": "28"} + }) + (cred_json, _, _) = \ + await anoncreds.issuer_create_credential(issuer_wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, None, None) + print_log('Credential: ') + pprint.pprint(json.loads(cred_json)) + + # 17. + print_log('\n17. Prover processes and stores received Credential\n') + await anoncreds.prover_store_credential(prover_wallet_handle, None, + cred_req_metadata_json, + cred_json, + cred_def_json, None) + + # 18. + print_log('\n18. Prover gets Credentials for Proof Request\n') + proof_request = { + 'nonce': '123432421212', + 'name': 'proof_req_1', + 'version': '0.1', + 'requested_attributes': { + 'attr1_referent': { + 'name': 'name', + "restrictions": { + "issuer_did": trust_anchor_did, + "schema_id": issuer_schema_id + } + } + }, + 'requested_predicates': { + 'predicate1_referent': { + 'name': 'age', + 'p_type': '>=', + 'p_value': 18, + "restrictions": { + "issuer_did": trust_anchor_did + } + } + } + } + print_log('Proof Request: ') + pprint.pprint(proof_request) + + # 19. + print_log('\n19. Prover gets Credentials for attr1_referent anf predicate1_referent\n') + proof_req_json = json.dumps(proof_request) + prover_cred_search_handle = \ + await anoncreds.prover_search_credentials_for_proof_req(prover_wallet_handle, proof_req_json, None) + + creds_for_attr1 = await anoncreds.prover_fetch_credentials_for_proof_req(prover_cred_search_handle, + 'attr1_referent', 1) + prover_cred_for_attr1 = json.loads(creds_for_attr1)[0]['cred_info'] + print_log('Prover credential for attr1_referent: ') + pprint.pprint(prover_cred_for_attr1) + + creds_for_predicate1 = await anoncreds.prover_fetch_credentials_for_proof_req(prover_cred_search_handle, + 'predicate1_referent', 1) + prover_cred_for_predicate1 = json.loads(creds_for_predicate1)[0]['cred_info'] + print_log('Prover credential for predicate1_referent: ') + pprint.pprint(prover_cred_for_predicate1) + + await anoncreds.prover_close_credentials_search_for_proof_req(prover_cred_search_handle) + + # 20. + print_log('\n20. Prover creates Proof for Proof Request\n') + prover_requested_creds = json.dumps({ + 'self_attested_attributes': {}, + 'requested_attributes': { + 'attr1_referent': { + 'cred_id': prover_cred_for_attr1['referent'], + 'revealed': True + } + }, + 'requested_predicates': { + 'predicate1_referent': { + 'cred_id': prover_cred_for_predicate1['referent'] + } + } + }) + print_log('Requested Credentials for Proving: ') + pprint.pprint(json.loads(prover_requested_creds)) + + prover_schema_id = json.loads(cred_offer_json)['schema_id'] + schemas_json = json.dumps({prover_schema_id: json.loads(issuer_schema_json)}) + cred_defs_json = json.dumps({cred_def_id: json.loads(cred_def_json)}) + proof_json = await anoncreds.prover_create_proof(prover_wallet_handle, + proof_req_json, + prover_requested_creds, + link_secret_id, + schemas_json, + cred_defs_json, + "{}") + proof = json.loads(proof_json) + assert 'Alex' == proof['requested_proof']['revealed_attrs']['attr1_referent']["raw"] + + # 21. + print_log('\n21. Verifier is verifying proof from Prover\n') + assert await anoncreds.verifier_verify_proof(proof_req_json, + proof_json, + schemas_json, + cred_defs_json, + "{}", "{}") + + # 22. + print_log('\n22. Closing both wallet_handles and pool\n') + await wallet.close_wallet(issuer_wallet_handle) + await wallet.close_wallet(prover_wallet_handle) + await pool.close_pool_ledger(pool_handle) + + # 23. + print_log('\n23. Deleting created wallet_handles\n') + await wallet.delete_wallet(issuer_wallet_config, issuer_wallet_credentials) + await wallet.delete_wallet(prover_wallet_config, prover_wallet_credentials) + + # 24. + print_log('\n24. Deleting pool ledger config\n') + await pool.delete_pool_ledger_config(pool_name) + + except IndyError as e: + print('Error occurred: %s' % e) + +def main(): + loop = asyncio.get_event_loop() + loop.run_until_complete(proof_negotiation()) + loop.close() + +if __name__ == '__main__': + main() + diff --git a/docs/how-tos/negotiate-proof/python/step2.py b/docs/how-tos/negotiate-proof/python/step2.py index becf7d8e91..67151d1701 100644 --- a/docs/how-tos/negotiate-proof/python/step2.py +++ b/docs/how-tos/negotiate-proof/python/step2.py @@ -1,72 +1,150 @@ # 1. - print_log('\n1. Creates Issuer wallet and opens it to get handle.\n') - await - wallet.create_wallet(pool_name, issuer_wallet_name, None, None, None) - issuer_wallet_handle = await - wallet.open_wallet(issuer_wallet_name, None, None) + print_log('\n1. opening a new local pool ledger configuration that will be used ' + 'later when connecting to ledger.\n') + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) + try: + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. - print_log('\n2. Creates Prover wallet and opens it to get handle.\n') - await - wallet.create_wallet(pool_name, prover_wallet_name, None, None, None) - prover_wallet_handle = await - wallet.open_wallet(prover_wallet_name, None, None) + print_log('\n2. Open pool ledger and get the handle from libindy\n') + pool_handle = await pool.open_pool_ledger(config_name=pool_name, config=None) # 3. - print_log('\n3. Issuer creates Claim Definition for Schema\n') - schema = { - 'seqNo': seq_no, - 'dest': issuer_did, - 'data': { - 'name': 'gvt', - 'version': '1.0', - 'attr_names': ['age', 'sex', 'height', 'name'] - } - } - schema_json = json.dumps(schema) - schema_key = { - 'name': schema['data']['name'], - 'version': schema['data']['version'], - 'did': schema['dest'], - } - claim_def_json = await - anoncreds.issuer_create_and_store_claim_def(issuer_wallet_handle, issuer_did, schema_json, 'CL', False) - print_log('Claim Definition: ') - pprint.pprint(json.loads(claim_def_json)) + print_log('\n3. Creating Issuer wallet and opening it to get the handle.\n') + issuer_wallet_handle = await open_wallet(issuer_wallet_config, issuer_wallet_credentials) # 4. - print_log('\n4. Prover creates Link Secret\n') - link_secret_name = 'link_secret' - await - anoncreds.prover_create_master_secret(prover_wallet_handle, link_secret_name) + print_log('\n4. Generating and storing steward DID and verkey\n') + steward_seed = '000000000000000000000000Steward1' + did_json = json.dumps({'seed': steward_seed}) + steward_did, steward_verkey = await did.create_and_store_my_did(issuer_wallet_handle, did_json) + print_log('Steward DID: ', steward_did) + print_log('Steward Verkey: ', steward_verkey) # 5. - print_log('\n5. Issuer create Cred Offer\n') - claim_offer_json = await - anoncreds.issuer_create_claim_offer(issuer_wallet_handle, schema_json, issuer_did, prover_did) - print_log('Claim Offer: ') - pprint.pprint(json.loads(claim_offer_json)) + print_log('\n5. Generating and storing trust anchor DID and verkey\n') + trust_anchor_did, trust_anchor_verkey = await did.create_and_store_my_did(issuer_wallet_handle, "{}") + print_log('Trust anchor DID: ', trust_anchor_did) + print_log('Trust anchor Verkey: ', trust_anchor_verkey) # 6. - print_log('\n6. Prover creates and stores Cred Request\n') - claim_req_json = await - anoncreds.prover_create_and_store_claim_req(prover_wallet_handle, prover_did, claim_offer_json, - claim_def_json, link_secret_name) - print_log('Claim Request: ') - pprint.pprint(json.loads(claim_req_json)) + print_log('\n6. Building NYM request to add Trust Anchor to the ledger\n') + nym_transaction_request = await ledger.build_nym_request(submitter_did=steward_did, + target_did=trust_anchor_did, + ver_key=trust_anchor_verkey, + alias=None, + role='TRUST_ANCHOR') + print_log('NYM transaction request: ') + pprint.pprint(json.loads(nym_transaction_request)) # 7. - print_log('\n7. Issuer creates Credential for received Cred Request\n') - claim_json = json.dumps({ - 'sex': ['male', '5944657099558967239210949258394887428692050081607692519917050011144233115103'], - 'name': ['Alex', '1139481716457488690172217916278103335'], - 'height': ['175', '175'], - 'age': ['28', '28'] - }) - (_, claim_json) = await - anoncreds.issuer_create_claim(issuer_wallet_handle, claim_req_json, claim_json, -1) + print_log('\n7. Sending NYM request to the ledger\n') + nym_transaction_response = await ledger.sign_and_submit_request(pool_handle=pool_handle, + wallet_handle=issuer_wallet_handle, + submitter_did=steward_did, + request_json=nym_transaction_request) + print_log('NYM transaction response: ') + pprint.pprint(json.loads(nym_transaction_response)) # 8. - print_log('\n8. Prover processes and stores received Credential\n') - await - anoncreds.prover_store_claim(prover_wallet_handle, claim_json, None) \ No newline at end of file + print_log('\n8. Issuer create Credential Schema\n') + schema = { + 'name': 'gvt', + 'version': '1.0', + 'attributes': '["age", "sex", "height", "name"]' + } + issuer_schema_id, issuer_schema_json = await anoncreds.issuer_create_schema(steward_did, + schema['name'], + schema['version'], + schema['attributes']) + print_log('Schema: ') + pprint.pprint(issuer_schema_json) + + # 9. + print_log('\n9. Build the SCHEMA request to add new schema to the ledger\n') + schema_request = await ledger.build_schema_request(steward_did, issuer_schema_json) + print_log('Schema request: ') + pprint.pprint(json.loads(schema_request)) + + # 10. + print_log('\n10. Sending the SCHEMA request to the ledger\n') + schema_response = \ + await ledger.sign_and_submit_request(pool_handle, + issuer_wallet_handle, + steward_did, + schema_request) + print_log('Schema response:') + pprint.pprint(json.loads(schema_response)) + + # 11. + print_log('\n11. Creating and storing Credential Definition using anoncreds as Trust Anchor, for the given Schema\n') + cred_def_tag = 'TAG1' + cred_def_type = 'CL' + cred_def_config = json.dumps({"support_revocation": False}) + + (cred_def_id, cred_def_json) = \ + await anoncreds.issuer_create_and_store_credential_def(issuer_wallet_handle, + trust_anchor_did, + issuer_schema_json, + cred_def_tag, + cred_def_type, + cred_def_config) + print_log('Credential definition: ') + pprint.pprint(json.loads(cred_def_json)) + + # 12. + print_log('\n12. Creating Prover wallet and opening it to get the handle.\n') + prover_did = 'VsKV7grR1BUE29mG2Fm2kX' + prover_wallet_config = json.dumps({"id": "prover_wallet"}) + prover_wallet_credentials = json.dumps({"key": "prover_wallet_key"}) + prover_wallet_handle = await open_wallet(prover_wallet_config, prover_wallet_credentials) + + # 13. + print_log('\n13. Prover is creating Link Secret\n') + prover_link_secret_name = 'link_secret' + link_secret_id = await anoncreds.prover_create_master_secret(prover_wallet_handle, + prover_link_secret_name) + + # 14. + print_log('\n14. Issuer (Trust Anchor) is creating a Credential Offer for Prover\n') + cred_offer_json = await anoncreds.issuer_create_credential_offer(issuer_wallet_handle, + cred_def_id) + print_log('Credential Offer: ') + pprint.pprint(json.loads(cred_offer_json)) + + # 15. + print_log('\n15. Prover creates Credential Request for the given credential offer\n') + (cred_req_json, cred_req_metadata_json) = \ + await anoncreds.prover_create_credential_req(prover_wallet_handle, + prover_did, + cred_offer_json, + cred_def_json, + prover_link_secret_name) + print_log('Credential Request: ') + pprint.pprint(json.loads(cred_req_json)) + + # 16. + print_log('\n16. Issuer (Trust Anchor) creates Credential for Credential Request\n') + cred_values_json = json.dumps({ + "sex": {"raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233"}, + "name": {"raw": "Alex", "encoded": "1139481716457488690172217916278103335"}, + "height": {"raw": "175", "encoded": "175"}, + "age": {"raw": "28", "encoded": "28"} + }) + (cred_json, _, _) = \ + await anoncreds.issuer_create_credential(issuer_wallet_handle, + cred_offer_json, + cred_req_json, + cred_values_json, None, None) + print_log('Credential: ') + pprint.pprint(json.loads(cred_json)) + + # 17. + print_log('\n17. Prover processes and stores received Credential\n') + await anoncreds.prover_store_credential(prover_wallet_handle, None, + cred_req_metadata_json, + cred_json, + cred_def_json, None) \ No newline at end of file diff --git a/docs/how-tos/negotiate-proof/python/step3.py b/docs/how-tos/negotiate-proof/python/step3.py index 2d765d5442..821ed83d17 100644 --- a/docs/how-tos/negotiate-proof/python/step3.py +++ b/docs/how-tos/negotiate-proof/python/step3.py @@ -1,31 +1,49 @@ - print_log('\n9. Prover gets Credentials for Proof Request\n') + # 18. + print_log('\n18. Prover gets Credentials for Proof Request\n') proof_request = { 'nonce': '123432421212', 'name': 'proof_req_1', 'version': '0.1', - 'requested_attrs': { + 'requested_attributes': { 'attr1_referent': { 'name': 'name', - 'restrictions': [{ - 'issuer_did': issuer_did, - 'schema_key': schema_key - }] + "restrictions": { + "issuer_did": trust_anchor_did, + "schema_id": issuer_schema_id + } } }, 'requested_predicates': { 'predicate1_referent': { - 'attr_name': 'age', + 'name': 'age', 'p_type': '>=', - 'value': 18, - 'restrictions': [{'issuer_did': issuer_did}] + 'p_value': 18, + "restrictions": { + "issuer_did": trust_anchor_did + } } } } print_log('Proof Request: ') pprint.pprint(proof_request) + + # 19. + print_log('\n19. Prover gets Credentials for attr1_referent anf predicate1_referent\n') proof_req_json = json.dumps(proof_request) - creds_for_proof_request_json = await - anoncreds.prover_get_claims_for_proof_req(prover_wallet_handle, proof_req_json) - creds_for_proof_request = json.loads(creds_for_proof_request_json) - print_log('Credentials for Proof Request: ') - pprint.pprint(creds_for_proof_request) + prover_cred_search_handle = \ + await anoncreds.prover_search_credentials_for_proof_req(prover_wallet_handle, proof_req_json, None) + + creds_for_attr1 = await anoncreds.prover_fetch_credentials_for_proof_req(prover_cred_search_handle, + 'attr1_referent', 1) + prover_cred_for_attr1 = json.loads(creds_for_attr1)[0]['cred_info'] + print_log('Prover credential for attr1_referent: ') + pprint.pprint(prover_cred_for_attr1) + + creds_for_predicate1 = await anoncreds.prover_fetch_credentials_for_proof_req(prover_cred_search_handle, + 'predicate1_referent', 1) + prover_cred_for_predicate1 = json.loads(creds_for_predicate1)[0]['cred_info'] + print_log('Prover credential for predicate1_referent: ') + pprint.pprint(prover_cred_for_predicate1) + + await anoncreds.prover_close_credentials_search_for_proof_req(prover_cred_search_handle) + \ No newline at end of file diff --git a/docs/how-tos/negotiate-proof/python/step4.py b/docs/how-tos/negotiate-proof/python/step4.py index 33aa8ee29a..abb12c25a2 100644 --- a/docs/how-tos/negotiate-proof/python/step4.py +++ b/docs/how-tos/negotiate-proof/python/step4.py @@ -1,24 +1,31 @@ - print_log('\n10. Prover creates Proof for Proof Request\n') - cred_for_attr_1 = creds_for_proof_request['attrs']['attr1_referent'] - referent = cred_for_attr_1[0]['referent'] - print_log('Referent: ') - pprint.pprint(referent) - chosen_claims_json = json.dumps({ + # 20. + print_log('\n20. Prover creates Proof for Proof Request\n') + prover_requested_creds = json.dumps({ 'self_attested_attributes': {}, - 'requested_attrs': { - 'attr1_referent': [referent, True] + 'requested_attributes': { + 'attr1_referent': { + 'cred_id': prover_cred_for_attr1['referent'], + 'revealed': True + } }, 'requested_predicates': { - 'predicate1_referent': referent + 'predicate1_referent': { + 'cred_id': prover_cred_for_predicate1['referent'] + } } }) - pprint.pprint(json.loads(chosen_claims_json)) - schemas_json = json.dumps({referent: schema}) - cdefs_json = json.dumps({referent: json.loads(cred_def_json)}) - revoc_regs_json = json.dumps({}) - proof_json = await - anoncreds.prover_create_proof(prover_wallet_handle, proof_req_json, chosen_claims_json, schemas_json, - 'link_secret', cdefs_json, revoc_regs_json) - proof = json.loads(proof_json) + print_log('Requested Credentials for Proving: ') + pprint.pprint(json.loads(prover_requested_creds)) - assert 'Alex' == proof['requested_proof']['revealed_attrs']['attr1_referent'][1] + prover_schema_id = json.loads(cred_offer_json)['schema_id'] + schemas_json = json.dumps({prover_schema_id: json.loads(issuer_schema_json)}) + cred_defs_json = json.dumps({cred_def_id: json.loads(cred_def_json)}) + proof_json = await anoncreds.prover_create_proof(prover_wallet_handle, + proof_req_json, + prover_requested_creds, + link_secret_id, + schemas_json, + cred_defs_json, + "{}") + proof = json.loads(proof_json) + assert 'Alex' == proof['requested_proof']['revealed_attrs']['attr1_referent']["raw"] \ No newline at end of file diff --git a/docs/how-tos/negotiate-proof/python/step5.py b/docs/how-tos/negotiate-proof/python/step5.py index 33aff17d89..ef2265c45c 100644 --- a/docs/how-tos/negotiate-proof/python/step5.py +++ b/docs/how-tos/negotiate-proof/python/step5.py @@ -1,17 +1,22 @@ - print_log('\n11.Verifier is verifying proof from Prover\n') - assert await - anoncreds.verifier_verify_proof(proof_req_json, proof_json, schemas_json, claim_defs_json, revoc_regs_json) + # 21. + print_log('\n21. Verifier is verifying proof from Prover\n') + assert await anoncreds.verifier_verify_proof(proof_req_json, + proof_json, + schemas_json, + cred_defs_json, + "{}", "{}") - # 12 - print_log('\n12. Closing both wallet_handles\n') - await - wallet.close_wallet(issuer_wallet_handle) - await - wallet.close_wallet(prover_wallet_handle) + # 22. + print_log('\n22. Closing both wallet_handles and pool\n') + await wallet.close_wallet(issuer_wallet_handle) + await wallet.close_wallet(prover_wallet_handle) + await pool.close_pool_ledger(pool_handle) - # 13 - print_log('\n13. Deleting created wallet_handles\n') - await - wallet.delete_wallet(prover_wallet_name, None) - await - wallet.delete_wallet(issuer_wallet_name, None) + # 23. + print_log('\n23. Deleting created wallet_handles\n') + await wallet.delete_wallet(issuer_wallet_config, issuer_wallet_credentials) + await wallet.delete_wallet(prover_wallet_config, prover_wallet_credentials) + + # 24. + print_log('\n24. Deleting pool ledger config\n') + await pool.delete_pool_ledger_config(pool_name) \ No newline at end of file diff --git a/docs/how-tos/negotiate-proof/python/template.py b/docs/how-tos/negotiate-proof/python/template.py index d814408960..0eb4b850ab 100644 --- a/docs/how-tos/negotiate-proof/python/template.py +++ b/docs/how-tos/negotiate-proof/python/template.py @@ -13,21 +13,16 @@ import asyncio import json import pprint -import sys -sys.path.insert(0, '/home/vagrant/code/evernym/indy-sdk/wrappers/python') +from indy import pool, ledger, wallet, did, anoncreds +from indy.error import ErrorCode, IndyError -from indy import pool, ledger, wallet, did, anoncreds, crypto -from indy.error import IndyError +from utils import open_wallet, get_pool_genesis_txn_path, PROTOCOL_VERSION - -seq_no = 1 pool_name = 'pool' -issuer_wallet_name = 'issuer_wallet' -prover_wallet_name = 'prover_wallet' -issuer_did = 'NcYxiDXkpYi6ov5FcYDi1e' -prover_did = 'VsKV7grR1BUE29mG2Fm2kX' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' +issuer_wallet_config = json.dumps({"id": "issuer_wallet"}) +issuer_wallet_credentials = json.dumps({"key": "issuer_wallet_key"}) +genesis_file_path = get_pool_genesis_txn_path(pool_name) def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -35,9 +30,10 @@ def print_log(value_color="", value_noncolor=""): ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - async def proof_negotiation(): try: + await pool.set_protocol_version(PROTOCOL_VERSION) + # Step 2 code goes here. # Step 3 code goes here. @@ -49,13 +45,11 @@ async def proof_negotiation(): except IndyError as e: print('Error occurred: %s' % e) - def main(): loop = asyncio.get_event_loop() loop.run_until_complete(proof_negotiation()) loop.close() - if __name__ == '__main__': main() diff --git a/docs/how-tos/negotiate-proof/python/utils.py b/docs/how-tos/negotiate-proof/python/utils.py new file mode 100644 index 0000000000..a130d1b49c --- /dev/null +++ b/docs/how-tos/negotiate-proof/python/utils.py @@ -0,0 +1,43 @@ +from os import environ +from pathlib import Path +from tempfile import gettempdir + +from indy import wallet +from indy.error import ErrorCode, IndyError + +PROTOCOL_VERSION = 2 + +def get_pool_genesis_txn_path(pool_name): + path_temp = Path(gettempdir()).joinpath("indy") + path = path_temp.joinpath("{}.txn".format(pool_name)) + save_pool_genesis_txn_file(path) + return path + +def pool_genesis_txn_data(): + pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") + + return "\n".join([ + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( + pool_ip, pool_ip) + ]) + +def save_pool_genesis_txn_file(path): + data = pool_genesis_txn_data() + path.parent.mkdir(parents=True, exist_ok=True) + with open(str(path), "w+") as f: + f.writelines(data) + +# Open and create wallet if not exists +async def open_wallet(wallet_config, wallet_credentials): + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError as ex: + if ex.error_code == ErrorCode.WalletAlreadyExistsError: + pass + return await wallet.open_wallet(wallet_config, wallet_credentials) \ No newline at end of file diff --git a/docs/how-tos/negotiate-proof/rust/README.md b/docs/how-tos/negotiate-proof/rust/README.md deleted file mode 100644 index fd387d810b..0000000000 --- a/docs/how-tos/negotiate-proof/rust/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Negotiate a Proof - -Indy-SDK Developer Walkthrough #5, Rust Edition - -[ [Python](../python/README.md) | [Java](../../not-yet-written.md) | [.NET](../../not-yet-written.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) ] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a rust editor of your -choice and paste the code from [template.rs](template.rs) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `negotiate-proof.rs`. - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -This how-to builds on the work in ["Issue Credential"](../issue-credential/../not-yet-written.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.rs](step2.rs) into -`negotiate-proof.rs` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `negotiate-proof.rs`. - -### Step 3 - -Proof negotiation typically begins when a *verifier* (also called a *relying party*) -requests proof. (As with credential issuance, the process has three logical -phases, but it is rare to begin with a proof offer. However, if an initial -proof request is met with a counter-offer, the offering phase of the -sequence becomes relevant.) - -![3 phases of proof negotiation; first phase is uncommon](../3-phases.png) - -A proof request is a JSON file that describes what sort of -proof would satisfy the relying party. - -Once the proof request is received, a holder of credentials must scan their -*identity wallet* to find out which credentials could be used to satisfy -the request. (Wallet scanning is inefficient, but this does not cause -problems for dozens or hundreds of credentials. At higher scale, a new -mechanism is needed. -[Work is underway](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g31e3a419cd_0_67) -to add index-driven search to indy wallets. Visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) -to learn more.) - -Copy the contents of [step3.rs](step3.rs) into -`negotiate-proof.rs` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `negotiate-proof.rs`. - -### Step 4 - -At this point, the holder becomes a *prover* by generating and presenting -a proof. This is done by building some JSON that selects the credentials -(out of those identified as valid candidates in the previous step), -that the prover wishes to use to satisfy the request. The prover calls -`anoncreds.prover_create_proof()` with appropriate parameters, and the -proof is created. - -Copy the contents of [step4.py](step4.py) into -`negotiate-proof.rs` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `negotiate-proof.rs`. - -### Step 6 - -Finally, the verifier needs to check to be sure the proof that's presented -satisfies their criteria. This is easy; just call `anoncreds.verifier_verify_proof()`. - -Copy the contents of [step5.rs](step5.rs) into -`negotiate-proof.rs` on top of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `negotiate-proof.rs`. - -### Step 6 - -Run the [finished code](negotiate-proof.rs) and observe the whole sequence. - -## More experiments - -You might try the ["Send a Secure Message"](../../send-secure-msg/../not-yet-written.md) -how-to. diff --git a/docs/how-tos/negotiate-proof/rust/src/negotiate-proof.rs b/docs/how-tos/negotiate-proof/rust/src/negotiate-proof.rs index dc2fdca9a7..2eccaa3a62 100644 --- a/docs/how-tos/negotiate-proof/rust/src/negotiate-proof.rs +++ b/docs/how-tos/negotiate-proof/rust/src/negotiate-proof.rs @@ -20,95 +20,94 @@ extern crate serde_json; // ------------------------------------------ // hyperledger crates // ------------------------------------------ -extern crate indy; // rust wrapper project +extern crate indyrs as indy; // rust wrapper project use std::env; use std::fs; use std::io::Write; use std::path::PathBuf; -use indy::did::Did; -use indy::anoncreds::Issuer; -use indy::ledger::Ledger; -use indy::pool::Pool; -use indy::anoncreds::Prover; -use indy::anoncreds::Verifier; -use indy::wallet::Wallet; +use indy::did; +use indy::future::Future; +use indy::ledger; +use indy::pool; +use indy::wallet; +use indy::anoncreds; const PROTOCOL_VERSION: usize = 2; static USEFUL_CREDENTIALS: &'static str = r#"{"key": "12345678901234567890123456789012"}"#; fn main() { - let wallet_name = "wallet"; - let pool_name = "pool"; + let wallet_name = "walletPP"; + let pool_name = "poolPP"; - indy::pool::Pool::set_protocol_version(PROTOCOL_VERSION).unwrap(); + indy::pool::set_protocol_version(PROTOCOL_VERSION).wait().unwrap(); println!("1. Creating a new local pool ledger configuration that can be used later to connect pool nodes"); let pool_config_file = create_genesis_txn_file_for_pool(pool_name); let pool_config = json!({ "genesis_txn" : &pool_config_file }); - Pool::create_ledger_config(&pool_name, Some(&pool_config.to_string())).unwrap(); + pool::create_pool_ledger_config(&pool_name, Some(&pool_config.to_string())).wait().unwrap(); println!("2. Open pool ledger and get the pool handle from libindy"); - let pool_handle: i32 = Pool::open_ledger(&pool_name, None).unwrap(); + let pool_handle: i32 = pool::open_pool_ledger(&pool_name, None).wait().unwrap(); println!("3. Creates a new wallet"); let config = json!({ "id" : wallet_name.to_string() }).to_string(); - Wallet::create(&config, USEFUL_CREDENTIALS).unwrap(); + wallet::create_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("4. Open wallet and get the wallet handle from libindy"); - let wallet_handle: i32 = Wallet::open(&config, USEFUL_CREDENTIALS).unwrap(); + let wallet_handle: i32 = wallet::open_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("5. Generating and storing steward DID and Verkey"); let first_json_seed = json!({ "seed":"000000000000000000000000Steward1" }).to_string(); - let (steward_did, _steward_verkey) = Did::new(wallet_handle, &first_json_seed).unwrap(); + let (steward_did, _steward_verkey) = did::create_and_store_my_did(wallet_handle, &first_json_seed).wait().unwrap(); println!("6. Generating and storing Trust Anchor DID and Verkey"); - let (trustee_did, trustee_verkey) = Did::new(wallet_handle, &"{}".to_string()).unwrap(); + let (trustee_did, trustee_verkey) = did::create_and_store_my_did(wallet_handle, &"{}".to_string()).wait().unwrap(); println!("7. Build NYM request to add Trust Anchor to the ledger"); - let build_nym_request: String = Ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).unwrap(); + let build_nym_request: String = ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).wait().unwrap(); println!("8. Sending the nym request to ledger"); - let _build_nym_sign_submit_result: String = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).unwrap(); + let _build_nym_sign_submit_result: String = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).wait().unwrap(); println!("9. Create Schema and Build the SCHEMA request to add new schema to the ledger as a Steward"); let name = "gvt"; let version = "1.0"; let attributes = r#"["age", "sex", "height", "name"]"#; - let (schema_id, schema_json) = Issuer::create_schema(&steward_did, name, version, attributes).unwrap(); + let (schema_id, schema_json) = anoncreds::issuer_create_schema(&steward_did, name, version, attributes).wait().unwrap(); - let build_schema_request: String = Ledger::build_schema_request(&steward_did, &schema_json).unwrap(); + let build_schema_request: String = ledger::build_schema_request(&steward_did, &schema_json).wait().unwrap(); println!("10. Sending the SCHEMA request to the ledger"); - let _signed_schema_request_response = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).unwrap(); + let _signed_schema_request_response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).wait().unwrap(); println!("11. Creating and storing CREDENTIAL DEFINITION using anoncreds as Trust Anchor, for the given Schema"); let config_json = r#"{ "support_revocation": false }"#; let tag = r#"TAG1"#; - let (cred_def_id, cred_def_json) = Issuer::create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).unwrap(); + let (cred_def_id, cred_def_json) = anoncreds::issuer_create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).wait().unwrap(); println!("12. Creating Prover wallet and opening it to get the handle"); let prover_did = "VsKV7grR1BUE29mG2Fm2kX"; let prover_wallet_name = "prover_wallet"; let prover_wallet_config = json!({ "id" : prover_wallet_name.to_string() }).to_string(); - Wallet::create(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); - let prover_wallet_handle: i32 = Wallet::open(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); + wallet::create_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); + let prover_wallet_handle: i32 = wallet::open_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); println!("13. Prover is creating Master Secret"); let master_secret_name = "master_secret"; - Prover::create_master_secret(prover_wallet_handle, Some(master_secret_name)).unwrap(); + anoncreds::prover_create_master_secret(prover_wallet_handle, Some(master_secret_name)).wait().unwrap(); println!("14. Issuer (Trust Anchor) is creating a Credential Offer for Prover"); - let cred_offer_json = Issuer::create_credential_offer(wallet_handle, &cred_def_id).unwrap(); + let cred_offer_json = anoncreds::issuer_create_credential_offer(wallet_handle, &cred_def_id).wait().unwrap(); println!("15. Prover creates Credential Request"); - let (cred_req_json, cred_req_metadata_json) = Prover::create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).unwrap(); + let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).wait().unwrap(); println!("16. Issuer (Trust Anchor) creates Credential for Credential Request"); @@ -122,10 +121,10 @@ fn main() { println!("cred_values_json = '{}'", &cred_values_json.to_string()); let (cred_json, _cred_revoc_id, _revoc_reg_delta_json) = - Issuer::create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).unwrap(); + anoncreds::issuer_create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).wait().unwrap(); println!("17. Prover processes and stores Credential"); - let _out_cred_id = Prover::store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).unwrap(); + let _out_cred_id = anoncreds::prover_store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).wait().unwrap(); println!("18. Prover gets Credentials for Proof Request"); let proof_req_json = json!({ @@ -154,7 +153,7 @@ fn main() { }); println!("Proof Request: {}", proof_req_json); - let creds_for_proof_request_json = Prover::get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json.to_string()).unwrap(); + let creds_for_proof_request_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json.to_string()).wait().unwrap(); println!("Credentials for Proof Request: {}", creds_for_proof_request_json); println!("19. Prover creates Proof for Proof Request"); @@ -186,13 +185,13 @@ fn main() { }).to_string(); let rev_states_json = json!({}).to_string(); - let proof_json = Prover::create_proof(prover_wallet_handle, + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, &proof_req_json.to_string(), &requested_credentials_json.to_string(), &master_secret_name, &schemas_json, &credential_defs_json, - &rev_states_json).unwrap(); + &rev_states_json).wait().unwrap(); let proof = serde_json::from_str::(&proof_json).unwrap(); assert_eq!("Alex", proof["requested_proof"]["revealed_attrs"]["attr1_referent"]["raw"].as_str().unwrap()); @@ -200,26 +199,26 @@ fn main() { let rev_reg_defs_json = json!({}).to_string(); let rev_regs_json = json!({}).to_string(); - let valid = Verifier::verify_proof(&proof_req_json.to_string(), + let valid = anoncreds::verifier_verify_proof(&proof_req_json.to_string(), &proof_json, &schemas_json, &credential_defs_json, &rev_reg_defs_json, &rev_regs_json - ).unwrap(); + ).wait().unwrap(); assert!(valid); // Clean UP println!("21. Close and delete two wallets"); - Wallet::close(prover_wallet_handle).unwrap(); - Wallet::delete(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); - Wallet::close(wallet_handle).unwrap(); - Wallet::delete(&config, USEFUL_CREDENTIALS).unwrap(); + wallet::close_wallet(prover_wallet_handle).wait().unwrap(); + wallet::delete_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); + wallet::close_wallet(wallet_handle).wait().unwrap(); + wallet::delete_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("22. Close pool and delete pool ledger config"); - Pool::close(pool_handle).unwrap(); - Pool::delete(&pool_name).unwrap(); + pool::close_pool_ledger(pool_handle).wait().unwrap(); + pool::delete_pool_ledger(&pool_name).wait().unwrap(); } fn create_genesis_txn_file_for_pool(pool_name: &str) -> String { diff --git a/docs/how-tos/negotiate-proof/rust/src/step2.rs b/docs/how-tos/negotiate-proof/rust/src/step2.rs index e57597f5af..9cfd406876 100644 --- a/docs/how-tos/negotiate-proof/rust/src/step2.rs +++ b/docs/how-tos/negotiate-proof/rust/src/step2.rs @@ -1,84 +1,84 @@ -indy::pool::Pool::set_protocol_version(PROTOCOL_VERSION).unwrap(); +indy::pool::set_protocol_version(PROTOCOL_VERSION).wait().unwrap(); println!("1. Creating a new local pool ledger configuration that can be used later to connect pool nodes"); let pool_config_file = create_genesis_txn_file_for_pool(pool_name); let pool_config = json!({ - "genesis_txn" : &pool_config_file - }); -Pool::create_ledger_config(&pool_name, Some(&pool_config.to_string())).unwrap(); + "genesis_txn" : &pool_config_file +}); +pool::create_pool_ledger_config(&pool_name, Some(&pool_config.to_string())).wait().unwrap(); println!("2. Open pool ledger and get the pool handle from libindy"); -let pool_handle: i32 = Pool::open_ledger(&pool_name, None).unwrap(); +let pool_handle: i32 = pool::open_pool_ledger(&pool_name, None).wait().unwrap(); println!("3. Creates a new wallet"); let config = json!({ "id" : wallet_name.to_string() }).to_string(); -Wallet::create(&config, USEFUL_CREDENTIALS).unwrap(); +wallet::create_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("4. Open wallet and get the wallet handle from libindy"); -let wallet_handle: i32 = Wallet::open(&config, USEFUL_CREDENTIALS).unwrap(); +let wallet_handle: i32 = wallet::open_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("5. Generating and storing steward DID and Verkey"); let first_json_seed = json!({ -"seed":"000000000000000000000000Steward1" + "seed":"000000000000000000000000Steward1" }).to_string(); -let (steward_did, _steward_verkey) = Did::new(wallet_handle, &first_json_seed).unwrap(); +let (steward_did, _steward_verkey) = did::create_and_store_my_did(wallet_handle, &first_json_seed).wait().unwrap(); println!("6. Generating and storing Trust Anchor DID and Verkey"); -let (trustee_did, trustee_verkey) = Did::new(wallet_handle, &"{}".to_string()).unwrap(); +let (trustee_did, trustee_verkey) = did::create_and_store_my_did(wallet_handle, &"{}".to_string()).wait().unwrap(); println!("7. Build NYM request to add Trust Anchor to the ledger"); -let build_nym_request: String = Ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).unwrap(); +let build_nym_request: String = ledger::build_nym_request(&steward_did, &trustee_did, Some(&trustee_verkey), None, Some("TRUST_ANCHOR")).wait().unwrap(); println!("8. Sending the nym request to ledger"); -let _build_nym_sign_submit_result: String = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).unwrap(); +let _build_nym_sign_submit_result: String = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_nym_request).wait().unwrap(); println!("9. Create Schema and Build the SCHEMA request to add new schema to the ledger as a Steward"); let name = "gvt"; let version = "1.0"; let attributes = r#"["age", "sex", "height", "name"]"#; -let (schema_id, schema_json) = Issuer::create_schema(&steward_did, name, version, attributes).unwrap(); +let (schema_id, schema_json) = anoncreds::issuer_create_schema(&steward_did, name, version, attributes).wait().unwrap(); -let build_schema_request: String = Ledger::build_schema_request(&steward_did, &schema_json).unwrap(); +let build_schema_request: String = ledger::build_schema_request(&steward_did, &schema_json).wait().unwrap(); println!("10. Sending the SCHEMA request to the ledger"); -let _signed_schema_request_response = Ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).unwrap(); +let _signed_schema_request_response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &steward_did, &build_schema_request).wait().unwrap(); println!("11. Creating and storing CREDENTIAL DEFINITION using anoncreds as Trust Anchor, for the given Schema"); let config_json = r#"{ "support_revocation": false }"#; let tag = r#"TAG1"#; -let (cred_def_id, cred_def_json) = Issuer::create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).unwrap(); +let (cred_def_id, cred_def_json) = anoncreds::issuer_create_and_store_credential_def(wallet_handle, &trustee_did, &schema_json, tag, None, config_json).wait().unwrap(); println!("12. Creating Prover wallet and opening it to get the handle"); let prover_did = "VsKV7grR1BUE29mG2Fm2kX"; let prover_wallet_name = "prover_wallet"; let prover_wallet_config = json!({ "id" : prover_wallet_name.to_string() }).to_string(); -Wallet::create(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); -let prover_wallet_handle: i32 = Wallet::open(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); +wallet::create_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); +let prover_wallet_handle: i32 = wallet::open_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); println!("13. Prover is creating Master Secret"); let master_secret_name = "master_secret"; -Prover::create_master_secret(prover_wallet_handle, Some(master_secret_name)).unwrap(); +anoncreds::prover_create_master_secret(prover_wallet_handle, Some(master_secret_name)).wait().unwrap(); println!("14. Issuer (Trust Anchor) is creating a Credential Offer for Prover"); -let cred_offer_json = Issuer::create_credential_offer(wallet_handle, &cred_def_id).unwrap(); +let cred_offer_json = anoncreds::issuer_create_credential_offer(wallet_handle, &cred_def_id).wait().unwrap(); println!("15. Prover creates Credential Request"); -let (cred_req_json, cred_req_metadata_json) = Prover::create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).unwrap(); +let (cred_req_json, cred_req_metadata_json) = anoncreds::prover_create_credential_req(prover_wallet_handle, prover_did, &cred_offer_json, &cred_def_json, &master_secret_name).wait().unwrap(); println!("16. Issuer (Trust Anchor) creates Credential for Credential Request"); let cred_values_json = json!({ - "sex": { "raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103" }, - "name": { "raw": "Alex", "encoded": "99262857098057710338306967609588410025648622308394250666849665532448612202874" }, - "height": { "raw": "175", "encoded": "175" }, - "age": { "raw": "28", "encoded": "28" }, - }); + "sex": { "raw": "male", "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103" }, + "name": { "raw": "Alex", "encoded": "99262857098057710338306967609588410025648622308394250666849665532448612202874" }, + "height": { "raw": "175", "encoded": "175" }, + "age": { "raw": "28", "encoded": "28" }, +}); println!("cred_values_json = '{}'", &cred_values_json.to_string()); let (cred_json, _cred_revoc_id, _revoc_reg_delta_json) = -Issuer::create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).unwrap(); + anoncreds::issuer_create_credential(wallet_handle, &cred_offer_json, &cred_req_json, &cred_values_json.to_string(), None, -1).wait().unwrap(); println!("17. Prover processes and stores Credential"); -let _out_cred_id = Prover::store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).unwrap(); +let _out_cred_id = anoncreds::prover_store_credential(prover_wallet_handle, None, &cred_req_metadata_json, &cred_json, &cred_def_json, None).wait().unwrap(); diff --git a/docs/how-tos/negotiate-proof/rust/src/step3.rs b/docs/how-tos/negotiate-proof/rust/src/step3.rs index b4688cd783..df477052fd 100644 --- a/docs/how-tos/negotiate-proof/rust/src/step3.rs +++ b/docs/how-tos/negotiate-proof/rust/src/step3.rs @@ -1,29 +1,29 @@ println!("18. Prover gets Credentials for Proof Request"); let proof_req_json = json!({ - "nonce": "123432421212", - "name": "proof_req_1", - "version": "0.1", - "requested_attributes": { - "attr1_referent": { - "name": "name", - "restrictions": { - "issuer_did": trustee_did, - "schema_id": schema_id - } + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "attr1_referent": { + "name": "name", + "restrictions": { + "issuer_did": trustee_did, + "schema_id": schema_id } - }, - "requested_predicates": { - "predicate1_referent": { - "name": "age", - "p_type": ">=", - "p_value": 18, - "restrictions": { - "issuer_did": trustee_did - } + } + }, + "requested_predicates": { + "predicate1_referent": { + "name": "age", + "p_type": ">=", + "p_value": 18, + "restrictions": { + "issuer_did": trustee_did } } - }); + } +}); println!("Proof Request: {}", proof_req_json); -let creds_for_proof_request_json = Prover::get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json.to_string()).unwrap(); +let creds_for_proof_request_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json.to_string()).wait().unwrap(); println!("Credentials for Proof Request: {}", creds_for_proof_request_json); diff --git a/docs/how-tos/negotiate-proof/rust/src/step4.rs b/docs/how-tos/negotiate-proof/rust/src/step4.rs index 08d5c47b5e..cef2d07446 100644 --- a/docs/how-tos/negotiate-proof/rust/src/step4.rs +++ b/docs/how-tos/negotiate-proof/rust/src/step4.rs @@ -4,35 +4,35 @@ let creds_for_attr_1 = &creds_for_proof_request["attrs"]["attr1_referent"]; let credential = &creds_for_attr_1[0]["cred_info"]; let requested_credentials_json = json!({ - "self_attested_attributes": {}, - "requested_attributes": { - "attr1_referent": { - "cred_id": credential["referent"].as_str().unwrap(), - "revealed": true - } - }, - "requested_predicates":{ - "predicate1_referent":{ - "cred_id": credential["referent"].as_str().unwrap(), - } + "self_attested_attributes": {}, + "requested_attributes": { + "attr1_referent": { + "cred_id": credential["referent"].as_str().unwrap(), + "revealed": true } - }); + }, + "requested_predicates":{ + "predicate1_referent":{ + "cred_id": credential["referent"].as_str().unwrap(), + } + } +}); println!("Requested Credentials for Proving: {}", requested_credentials_json.to_string()); let schemas_json = json!({ -schema_id.as_str(): serde_json::from_str::(&schema_json).unwrap() + schema_id.as_str(): serde_json::from_str::(&schema_json).unwrap() }).to_string(); let credential_defs_json = json!({ -cred_def_id.as_str(): serde_json::from_str::(&cred_def_json).unwrap() + cred_def_id.as_str(): serde_json::from_str::(&cred_def_json).unwrap() }).to_string(); let rev_states_json = json!({}).to_string(); -let proof_json = Prover::create_proof(prover_wallet_handle, -&proof_req_json.to_string(), -&requested_credentials_json.to_string(), -&master_secret_name, -&schemas_json, -&credential_defs_json, -&rev_states_json).unwrap(); +let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json.to_string(), + &requested_credentials_json.to_string(), + &master_secret_name, + &schemas_json, + &credential_defs_json, + &rev_states_json).wait().unwrap(); let proof = serde_json::from_str::(&proof_json).unwrap(); -assert_eq!("Alex", proof["requested_proof"]["revealed_attrs"]["attr1_referent"]["raw"].as_str().unwrap()); \ No newline at end of file +assert_eq!("Alex", proof["requested_proof"]["revealed_attrs"]["attr1_referent"]["raw"].as_str().unwrap()); diff --git a/docs/how-tos/negotiate-proof/rust/src/step5.rs b/docs/how-tos/negotiate-proof/rust/src/step5.rs index fdd165cad2..0b6c654764 100644 --- a/docs/how-tos/negotiate-proof/rust/src/step5.rs +++ b/docs/how-tos/negotiate-proof/rust/src/step5.rs @@ -2,23 +2,23 @@ println!("20. Verifier is verifying proof from Prover"); let rev_reg_defs_json = json!({}).to_string(); let rev_regs_json = json!({}).to_string(); -let valid = Verifier::verify_proof(&proof_req_json.to_string(), -&proof_json, -&schemas_json, -&credential_defs_json, -&rev_reg_defs_json, -&rev_regs_json -).unwrap(); +let valid = anoncreds::verifier_verify_proof(&proof_req_json.to_string(), + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json +).wait().unwrap(); assert!(valid); // Clean UP println!("21. Close and delete two wallets"); -Wallet::close(prover_wallet_handle).unwrap(); -Wallet::delete(&prover_wallet_config, USEFUL_CREDENTIALS).unwrap(); -Wallet::close(wallet_handle).unwrap(); -Wallet::delete(&config, USEFUL_CREDENTIALS).unwrap(); +wallet::close_wallet(prover_wallet_handle).wait().unwrap(); +wallet::delete_wallet(&prover_wallet_config, USEFUL_CREDENTIALS).wait().unwrap(); +wallet::close_wallet(wallet_handle).wait().unwrap(); +wallet::delete_wallet(&config, USEFUL_CREDENTIALS).wait().unwrap(); println!("22. Close pool and delete pool ledger config"); -Pool::close(pool_handle).unwrap(); -Pool::delete(&pool_name).unwrap(); \ No newline at end of file +pool::close_pool_ledger(pool_handle).wait().unwrap(); +pool::delete_pool_ledger(&pool_name).wait().unwrap(); diff --git a/docs/how-tos/negotiate-proof/rust/src/template.rs b/docs/how-tos/negotiate-proof/rust/src/template.rs index bfee228352..1796537cf7 100644 --- a/docs/how-tos/negotiate-proof/rust/src/template.rs +++ b/docs/how-tos/negotiate-proof/rust/src/template.rs @@ -20,20 +20,19 @@ extern crate serde_json; // ------------------------------------------ // hyperledger crates // ------------------------------------------ -extern crate indy; // rust wrapper project +extern crate indyrs as indy; // rust wrapper project use std::env; use std::fs; use std::io::Write; use std::path::PathBuf; -use indy::did::Did; -use indy::ledger::Ledger; -use indy::pool::Pool; -use indy::wallet::Wallet; -use indy::anoncreds::Issuer; -use indy::anoncreds::Prover; -use indy::anoncreds::Verifier; +use indy::did; +use indy::future::Future; +use indy::ledger; +use indy::pool; +use indy::wallet; +use indy::anoncreds; const PROTOCOL_VERSION: usize = 2; static USEFUL_CREDENTIALS: &'static str = r#"{"key": "12345678901234567890123456789012"}"#; diff --git a/docs/how-tos/prerequisites.md b/docs/how-tos/prerequisites.md index 9551f6a42f..2d20b7df19 100644 --- a/docs/how-tos/prerequisites.md +++ b/docs/how-tos/prerequisites.md @@ -13,3 +13,16 @@ recommend building the SDK to eliminate versioning problems; pre-built binaries may be slightly stale. Instructions for running an indy pool can be found [here](../../README.md#how-to-start-local-nodes-pool-with-docker). + +## Wrapper's specific prerequisites + +# C# +Additionally (and depending on your environment), you will need .NET installed. These demos were tested with .NET Core 2.1.302. + +# Nodejs +Install all dependencies running `npm install`. + +# Python +Ensure you have the 64-bit version of Python 3 installed, as the 32-bit version may have problems loading the Indy .dll files. + +Install the required python packages by executing: `$ pip install python3-indy asyncio` \ No newline at end of file diff --git a/docs/how-tos/rotate-key/README.md b/docs/how-tos/rotate-key/README.md index 0cce919af8..f0ee46c724 100644 --- a/docs/how-tos/rotate-key/README.md +++ b/docs/how-tos/rotate-key/README.md @@ -3,4 +3,75 @@ This shows how to change the verkey that the ledger associates with a DID. It builds on ["Write DID and Query Its Verkey"](../write-did-and-query-verkey/README.md). -[ [Python](python/README.md) | [Java](java/README.md) | [.NET](../not-yet-written.md) | [Node.js](nodejs/README.md) | [Objective C](../not-yet-written.md) | [Rust](rust/README.md) ] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `rotate_key.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `rotate_key.py`, for nodejs: `rotate_key.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](java/template.java) | [Node.js template](nodejs/template.js) | [Rust template](rust/src/template.rs)] + +### Step 2 + +This how-to builds on the work in +["Write DID and Query Verkey"](../write-did-and-query-verkey/README.md). +Rather than duplicate our explanation of those steps here, we will simply +copy that code as our starting point. + +Copy the contents of the correspondent *step2* file below into your `rotate_key` file +instead of the `Step 2 code goes here` placeholder comment, and save it. + +[ [Python step2](python/step2.py) | [Java step2](java/step2.java) | [Node.js step2](nodejs/step2.js) | [Rust step2](rust/src/step2.rs)] + +### Step 3 + +Once we have an identity on the ledger, we can rotate its key pair. + +Copy the contents of the correspondent *step3* file below into your `rotate_key` file instead of the `Step 3 code goes here` placeholder comment. + +[ [Python step3](python/step3.py) | [Java step3](java/step3.java) | [Node.js step3](nodejs/step3.js) | [Rust step3](rust/src/step3.rs)] + +Most of the logic here should be self-explanatory. However, it's worth +explaining the paired functions `replace_keys_start` and `replace_keys_apply`. +When we submit the update transaction to the ledger, we have to sign it +using the current signing key; the ledger will verify this using the +verkey that it recognizes. Yet we have to specify the new verkey value +in the transaction itself. The `replace_keys_start` method tells the wallet +that an update is pending, and that it should track both the new and old keypairs +for the identity. The `replace_keys_apply` resolves the pending status +so the new value becomes canonical in the local wallet (after it has +already become canonical on the ledger). + +### Step 4 + +Now we can query the ledger to see which verkey it has on record for the +identity. + +Copy the contents of *step4* file below into your `rotate_key` file instead of +the `Step 4 code goes here` placeholder comment. + +[ [Python step4](python/step4.py) | [Java step4](java/step4.java) | [Node.js step4](nodejs/step4.js) | [Rust step4](rust/src/step4.rs)] + +Only a handful of lines of code matter to our goal here; the rest of this +block is comments and boilerplate cleanup **(which you should not omit!)**. + +### Step 5 + +Run the completed demo and observe the whole sequence. + +[ [Python complete](python/rotate_key.py) | [Java complete](java/RotateKey.java) | [Node.js complete](nodejs/rotateKey.js) | [Rust complete](rust/src/rotate-key.rs)] + +## More experiments + +You might try the ["Save a Schema and Cred Def"](../save-schema-and-cred-def/README.md) +how-to. diff --git a/docs/how-tos/rotate-key/java/README.md b/docs/how-tos/rotate-key/java/README.md deleted file mode 100644 index 74c61ab4b5..0000000000 --- a/docs/how-tos/rotate-key/java/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Rotate a Key - -Indy-SDK Developer Walkthrough #2, Java Edition - -[ [Python](../python/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a java editor of your -choice and paste the code from [template.java](template.java) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `RotateKey.java`. - -### Step 2 - -This how-to builds on the work in -["Write DID and Query Verkey"](../../write-did-and-query-verkey/java/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.java](step2.java) into -`RotateKey.java` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `RotateKey.java`. - -### Step 3 - -Once we have an identity on the ledger, we can rotate its key pair. - -Copy the contents of [step3.java](step3.java) into -`RotateKey.java` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `RotateKey.java`. - -Most of the logic here should be self-explanatory. However, it's worth -explaining the paired functions `replaceKeysStart()` and `replaceKeysApply()`. -When we submit the update transaction to the ledger, we have to sign it -using the current signing key; the ledger will verify this using the -verkey that it recognizes. Yet we have to specify the new verkey value -in the transaction itself. The `replaceKeysStart()` method tells the wallet -that an update is pending, and that it should track both the new and old keypairs -for the identity. The `replaceKeysApply()` resolves the pending status -so the new value becomes canonical in the local wallet (after it has -already become canonical on the ledger). - -### Step 4 - -Now we can query the ledger to see which verkey it has on record for the -identity. - -Copy the contents of [step4.java](step4.java) into -`RotateKey.java` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `RotateKey.java`. - -Only a handful of lines of code matter to our goal here; the rest of this -block is comments and boilerplate cleanup **(which you should not omit!)**. - -### Step 5 - -Run the completed demo and observe the whole sequence. - -## More experiments - -TBD diff --git a/docs/how-tos/rotate-key/java/RotateKeyOnTheLedger.java b/docs/how-tos/rotate-key/java/RotateKey.java similarity index 99% rename from docs/how-tos/rotate-key/java/RotateKeyOnTheLedger.java rename to docs/how-tos/rotate-key/java/RotateKey.java index 6692b239cc..86cd95222e 100644 --- a/docs/how-tos/rotate-key/java/RotateKeyOnTheLedger.java +++ b/docs/how-tos/rotate-key/java/RotateKey.java @@ -14,7 +14,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -public class RotateKeyOnTheLedger { +public class RotateKey { static void demo() throws Exception { String walletName = "myWallet"; String poolName = "pool"; diff --git a/docs/how-tos/rotate-key/nodejs/README.md b/docs/how-tos/rotate-key/nodejs/README.md deleted file mode 100644 index 966710bd1b..0000000000 --- a/docs/how-tos/rotate-key/nodejs/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Rotate a Key - -Indy-SDK Developer Walkthrough #2, NodeJS Edition - -[ [Python](../python/README.md) | [Java](../java/README.md) | [.NET](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Install all dependencies running `npm install`. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a python editor of your -choice and paste the code from [template.js](template.js) -into a new file. We will be modifying this code in later steps. - -Save the file as `rotateKeyOnTheLedger.js`. - -### Step 2 - -This how-to builds on the work in -["Write DID and Query Verkey"](../../write-did-and-query-verkey/nodejs/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.js](step2.js) into -`rotateKeyOnTheLedger.js` instead of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `rotateKeyOnTheLedger.js`. - -### Step 3 - -Once we have an identity on the ledger, we can rotate its key pair. - -Copy the contents of [step3.js](step3.js) into -`rotateKeyOnTheLedger.js` instead of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `rotateKeyOnTheLedger.js`. - -Most of the logic here should be self-explanatory. However, it's worth -explaining the paired functions `replace_keys_start` and `replace_keys_apply`. -When we submit the update transaction to the ledger, we have to sign it -using the current signing key; the ledger will verify this using the -verkey that it recognizes. Yet we have to specify the new verkey value -in the transaction itself. The `replace_keys_start` method tells the wallet -that an update is pending, and that it should track both the new and old keypairs -for the identity. The `replace_keys_apply` resolves the pending status -so the new value becomes canonical in the local wallet (after it has -already become canonical on the ledger). - -### Step 4 - -Now we can query the ledger to see which verkey it has on record for the -identity. - -Copy the contents of [step4.js](step4.js) into -`rotateKeyOnTheLedger.js` instead of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `rotateKeyOnTheLedger.js`. - -Only a handful of lines of code matter to our goal here; the rest of this -block is comments and boilerplate cleanup **(which you should not omit!)**. - -### Step 5 - -Run the completed demo and observe the whole sequence. - -## More experiments - -You might try the ["Save a Schema and Cred Def"](../../save-schema-and-cred-def/nodejs/README.md) -how-to. diff --git a/docs/how-tos/rotate-key/nodejs/package.json b/docs/how-tos/rotate-key/nodejs/package.json index 4be9c88dc8..05cae21cdf 100644 --- a/docs/how-tos/rotate-key/nodejs/package.json +++ b/docs/how-tos/rotate-key/nodejs/package.json @@ -3,9 +3,9 @@ "version": "1.0.0", "private": true, "description": "Demonstrates using NodeJs wrapper for LibIndy through changing the verkey that the ledger associates with a DID", - "main": "rotateKeyOnTheLedger.js", + "main": "rotateKey.js", "scripts": { - "start": "node rotateKeyOnTheLedger.js", + "start": "node rotateKey.js", "ledger:start": "cd ../../../../ && docker build -f ci/indy-pool.dockerfile -t indy_pool . && docker run --name indy_pool -itd -p 9701-9708:9701-9708 indy_pool", "ledger:stop": "docker stop indy_pool && docker rm indy_pool" }, diff --git a/docs/how-tos/rotate-key/nodejs/rotateKeyOnTheLedger.js b/docs/how-tos/rotate-key/nodejs/rotateKey.js similarity index 100% rename from docs/how-tos/rotate-key/nodejs/rotateKeyOnTheLedger.js rename to docs/how-tos/rotate-key/nodejs/rotateKey.js diff --git a/docs/how-tos/rotate-key/python/README.md b/docs/how-tos/rotate-key/python/README.md deleted file mode 100644 index 1b6c0a950f..0000000000 --- a/docs/how-tos/rotate-key/python/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# Rotate a Key - -Indy-SDK Developer Walkthrough #2, Python Edition - -[ [Java](../java/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Ensure you have the 64-bit version of Python 3 installed, as the 32-bit version may have problems loading the Indy .dll files. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a python editor of your -choice and paste the code from [template.py](template.py) -into a new file. We will be modifying this code in later steps. - -Save the file as `rotate_key.py`. - -Install the required python packages by executing `$ pip install python3-indy asyncio` - - -### Step 2 - -This how-to builds on the work in -["Write DID and Query Verkey"](../../write-did-and-query-verkey/python/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.py](step2.py) into -`rotate_key.py` instead of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `rotate_key.py`. - -### Step 3 - -Once we have an identity on the ledger, we can rotate its key pair. - -Copy the contents of [step3.py](step3.py) into -`rotate_key.py` instead of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `rotate_key.py`. - -Most of the logic here should be self-explanatory. However, it's worth -explaining the paired functions `replace_keys_start` and `replace_keys_apply`. -When we submit the update transaction to the ledger, we have to sign it -using the current signing key; the ledger will verify this using the -verkey that it recognizes. Yet we have to specify the new verkey value -in the transaction itself. The `replace_keys_start` method tells the wallet -that an update is pending, and that it should track both the new and old keypairs -for the identity. The `replace_keys_apply` resolves the pending status -so the new value becomes canonical in the local wallet (after it has -already become canonical on the ledger). - -### Step 4 - -Now we can query the ledger to see which verkey it has on record for the -identity. - -Copy the contents of [step4.py](step4.py) into -`rotate_key.py` instead of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `rotate_key.py`. - -Only a handful of lines of code matter to our goal here; the rest of this -block is comments and boilerplate cleanup **(which you should not omit!)**. - -### Step 5 - -Run the completed demo and observe the whole sequence. - -## More experiments - -You might try the ["Save a Schema and Cred Def"](../../save-schema-and-cred-def/python/README.md) -how-to. - -## Common errors -Error `PoolLedgerConfigAlreadyExistsError`. -Delete config before creating: -```python -try: - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) -except IndyError: - await pool.delete_pool_ledger_config(config_name=pool_name) - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) -``` - -Error `WalletAlreadyExistsError`. -Delete wallet before creating: -```python -try: - await wallet.create_wallet(pool_name, wallet_name, None, None, wallet_credentials) -except IndyError: - await wallet.delete_wallet(wallet_name, wallet_credentials) - await wallet.create_wallet(pool_name, wallet_name, None, None, wallet_credentials) -``` - -Error `CommonIOError`. Make sure that you have set `genesis_file_path` to point -to your `indy-sdk/cli/docker_pool_transactions_genesis`. - -Error `PoolLedgerTimeout`. Make sure that the pool of local nodes in Docker is running on the same ip/ports as -in the `docker_pool_transactions_genesis` (for further details see [How to start local nodes pool with docker](https://github.com/hyperledger/indy-sdk/blob/master/README.md#how-to-start-local-nodes-pool-with-docker)) diff --git a/docs/how-tos/rotate-key/python/rotate_key_on_the_ledger.py b/docs/how-tos/rotate-key/python/rotate_key.py similarity index 92% rename from docs/how-tos/rotate-key/python/rotate_key_on_the_ledger.py rename to docs/how-tos/rotate-key/python/rotate_key.py index 49763ca8bf..ab10ceb391 100644 --- a/docs/how-tos/rotate-key/python/rotate_key_on_the_ledger.py +++ b/docs/how-tos/rotate-key/python/rotate_key.py @@ -15,16 +15,14 @@ added by Steward """ - import asyncio import json import pprint from indy import pool, ledger, wallet, did -from indy.error import IndyError - -from src.utils import get_pool_genesis_txn_path, PROTOCOL_VERSION +from indy.error import IndyError, ErrorCode +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' genesis_file_path = get_pool_genesis_txn_path(pool_name) @@ -32,16 +30,12 @@ wallet_config = json.dumps({"id": "wallet"}) wallet_credentials = json.dumps({"key": "wallet_key"}) -# Set protocol version to 2 to work with the current version of Indy Node -PROTOCOL_VERSION = 2 - def print_log(value_color="", value_noncolor=""): """set the colors for text.""" HEADER = '\033[92m' ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - async def rotate_key_on_the_ledger(): try: await pool.set_protocol_version(PROTOCOL_VERSION) @@ -50,7 +44,11 @@ async def rotate_key_on_the_ledger(): print_log('1. Creates a new local pool ledger configuration that is used ' 'later when connecting to ledger.\n') pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + try: + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. print_log('\n2. Open pool ledger and get handle from libindy\n') @@ -58,7 +56,11 @@ async def rotate_key_on_the_ledger(): # 3. print_log('\n3. Creating new secure wallet with the given unique name\n') - await wallet.create_wallet(wallet_config, wallet_credentials) + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError as ex: + if ex.error_code == ErrorCode.WalletAlreadyExistsError: + pass # 4. print_log('\n4. Open wallet and get handle from libindy to use in methods that require wallet access\n') diff --git a/docs/how-tos/rotate-key/python/utils.py b/docs/how-tos/rotate-key/python/utils.py new file mode 100644 index 0000000000..a9bdd66d86 --- /dev/null +++ b/docs/how-tos/rotate-key/python/utils.py @@ -0,0 +1,31 @@ +from os import environ +from pathlib import Path +from tempfile import gettempdir + +PROTOCOL_VERSION = 2 + +def get_pool_genesis_txn_path(pool_name): + path_temp = Path(gettempdir()).joinpath("indy") + path = path_temp.joinpath("{}.txn".format(pool_name)) + save_pool_genesis_txn_file(path) + return path + +def pool_genesis_txn_data(): + pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") + + return "\n".join([ + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( + pool_ip, pool_ip) + ]) + +def save_pool_genesis_txn_file(path): + data = pool_genesis_txn_data() + path.parent.mkdir(parents=True, exist_ok=True) + with open(str(path), "w+") as f: + f.writelines(data) diff --git a/docs/how-tos/rotate-key/rust/README.md b/docs/how-tos/rotate-key/rust/README.md deleted file mode 100644 index cf78c06682..0000000000 --- a/docs/how-tos/rotate-key/rust/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Rotate a Key - -Indy-SDK Developer Walkthrough #2, Rust Edition - -[ [Python](../python/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Java](../java/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a rust editor of your -choice and paste the code from [template.rs](template.rs) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `rotate-key.rs`. - -### Step 2 - -This how-to builds on the work in -["Write DID and Query Verkey"](../../write-did-and-query-verkey/rust/README.md). -Rather than duplicate our explanation of those steps here, we will simply -copy that code as our starting point. - -Copy the contents of [step2.rs](step2.rs) into -`rotate-key.rs` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `rotate-key.rs`. - -### Step 3 - -Once we have an identity on the ledger, we can rotate its key pair. - -Copy the contents of [step3.rs](step3.rs) into -`rotate-key.rs` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `rotate-key.rs`. - -Most of the logic here should be self-explanatory. However, it's worth -explaining the paired functions `replace_keys_start()` and `replace_keys_apply()`. -When we submit the update transaction to the ledger, we have to sign it -using the current signing key; the ledger will verify this using the -verkey that it recognizes. Yet we have to specify the new verkey value -in the transaction itself. The `replace_keys_start()` method tells the wallet -that an update is pending, and that it should track both the new and old keypairs -for the identity. The `replace_keys_apply()` resolves the pending status -so the new value becomes canonical in the local wallet (after it has -already become canonical on the ledger). - -### Step 4 - -Now we can query the ledger to see which verkey it has on record for the -identity. - -Copy the contents of [step4.rs](step4.rs) into -`rotate-key.rs` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `rotate-key.rs`. - -Only a handful of lines of code matter to our goal here; the rest of this -block is comments and boilerplate cleanup **(which you should not omit!)**. - -### Step 5 - -Run the completed demo and observe the whole sequence. - -## More experiments - -TBD diff --git a/docs/how-tos/save-schema-and-cred-def/README.md b/docs/how-tos/save-schema-and-cred-def/README.md index 045769b2de..dd22764155 100644 --- a/docs/how-tos/save-schema-and-cred-def/README.md +++ b/docs/how-tos/save-schema-and-cred-def/README.md @@ -3,4 +3,100 @@ This shows how to save a schema and credential definition on the ledger, which is a prerequisite for ["Issue Credential"](../issue-credential/README.md). -[ [Python](python/README.md) | [Java](java/README.md) | [.NET](../not-yet-written.md) | [Node.js](../not-yet-written.md) | [Objective C](../not-yet-written.md) | [Rust](rust/README.md)] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `save_schema_and_cred_def.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `save_schema_and_cred_def.py`, for nodejs: `save_schema_and_cred_def.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](java/template.java) | [Rust template](rust/src/template.rs)] + +This is a very simple app framework into which you'll plug the code you'll be writing. + +### Step 2 + +Now we need to give the SDK some context that it will need +to deal with an indy ledger. This requires us to point the SDK at some +*genesis transactions* that tell the SDK how to contact the ledger on +the network, and how to trust that the nodes it contacts possess +appropriate keys. +We also need to create a wallet so the SDK can store +DIDs and the key material we're going to use. Also, we need +to create a trust anchor identity that has privileges to create schemas +and credential definitions. + +All of these steps are similar to those in simpler how-tos, such as +["Write a DID and Query Its Verkey"](../write-did-and-query-verkey/README.md). +We'll get this housekeeping out of the way in a single step here, +rather than dwelling on its details. + +Copy the contents of the correspondent *step2* file below into your `save_schema_and_cred_def` file instead of the `Step 2 code goes here` +placeholder comment, and save it. + +[ [Python step2](python/step2.py) | [Java step2](java/step2.java) | [Rust step2](rust/src/step2.rs)] + +Study the changes. Scaffolding code like this is likely to appear in anything +that uses indy. + +### Step 3 + +Now we need to create and define a schema. Schemas in indy are very simple +JSON documents that specify their name and version, and that list attributes +that will appear in a credential. Today, they do not describe data type, +recurrence rules, nesting, and other elaborate constructs. There is work +underway to make them fancier; visit +[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) to learn +more. + +A sample schema might look like this: + +```json +{ + "id": "1", + "name": "gvt", + "version": "1.0", + "ver": "1.0", + "attrNames": ["age", "sex", "height", "name"] +} +``` + +Copy the contents of the correspondent *step3* file below into your `save_schema_and_cred_def` file instead of the `Step 3 code goes here` placeholder comment. + +[ [Python step3](python/step3.py) | [Java step3](java/step3.java) | [Rust step3](rust/src/step3.rs)] + +Notice how this schema is submitted to the ledger by the steward +identity we created previously. + +### Step 4 + +Next, we create a *credential definition*. This references the schema +that we just added, and announces who is going to be issuing credentials +with that schema (our trust anchor identity, in this case), what type of +signature method they plan to use ("CL" = "Camenisch Lysyanskya", the +default method used for zero-knowledge proofs by indy), how they +plan to handle revocation, and so forth. + +Copy the contents of *step4* file below into your `save_schema_and_cred_def` file instead of the `Step 4 code goes here` placeholder comment. + +[ [Python step4](python/step4.py) | [Java step4](java/step4.java) | [Rust step4](rust/src/step4.rs)] + +### Step 5 + +Run the completed demo and observe the whole sequence. + +[ [Python complete](python/save_schema_and_cred_def.py) | [Java complete](java/SaveSchemaAndCredDef.java) | [Rust complete](rust/src/save-schema-and-cred-def.rs)] + +## More experiments + +You might try the ["Issue a Credential"](../issue-credential/README.md) +how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/save-schema-and-cred-def/java/README.md b/docs/how-tos/save-schema-and-cred-def/java/README.md deleted file mode 100644 index e4bc574a35..0000000000 --- a/docs/how-tos/save-schema-and-cred-def/java/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# Save a Schema and Credential Definition - -Indy-SDK Developer Walkthrough #4, Java Edition - -[ [Python](../python/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a java editor of your -choice and paste the code from [template.java](template.java) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `SaveSchemaAndCredDef.java` - -This is a simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -We need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network and how to trust that the nodes it contacts possess -appropriate keys. We also need to create a wallet so the SDK can store -DIDs and the key material we're going to use. Also, we need -to create a trust anchor identity that has privileges to create schemas -and credential definitions. - -All of these steps are similar to those in simpler how-tos, such as -["Write a DID and Query Its Verkey"](../../write-did-and-query-verkey/java/README.md). -We'll get this housekeeping out of -the way in a single step here, rather than dwelling on its details. - -Copy the contents of [step2.java](step2.java) into -`SaveSchemaAndCredDef.java` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `SaveSchemaAndCredDef.java`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to create and define a schema. Schemas in indy are very simple -JSON documents that specify their name and version, and that list attributes -that will appear in a credential. Today, they do not describe data type, -recurrence rules, nesting, and other elaborate constructs. There is work -underway to make them fancier; visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) to learn -more. - -A sample schema might look like this: - -```json -{ - "name": "simple_gvt_credential", - "version": "1.0", - "attr_names": ["age", "gender", "height", "name"] -} -``` - -Copy the contents of [step3.java](step3.java) into -`SaveSchemaAndCredDef.java` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `SaveSchemaAndCredDef.java`. - -Notice how this schema is submitted to the ledger by the steward -identity we created previously. - -### Step 4 - -Next, we create a *credential definition*. This references the schema -that we just added, and announces who is going to be issuing credentials -with that schema (our trust anchor identity, in this case), what type of -signature method they plan to use ("CL" = "Camenisch Lysyanskya", the -default method used for zero-knowledge proofs by indy), how they -plan to handle revocation, and so forth. - -Copy the contents of [step4.java](step4.java) into -`SaveSchemaAndCredDef.java` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `SaveSchemaAndCredDef.java`. - -### Step 5 - -Run the [finished code](SaveSchemaAndCredDef.java) and observe the whole sequence. - -## More experiments - -You might try the ["Issue a Credential"](../../issue-cred/../not-yet-written.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/save-schema-and-cred-def/java/SaveSchemaAndCredDef.java b/docs/how-tos/save-schema-and-cred-def/java/SaveSchemaAndCredDef.java index d64c775992..ab17cfe474 100644 --- a/docs/how-tos/save-schema-and-cred-def/java/SaveSchemaAndCredDef.java +++ b/docs/how-tos/save-schema-and-cred-def/java/SaveSchemaAndCredDef.java @@ -6,25 +6,31 @@ import static org.hyperledger.indy.sdk.anoncreds.Anoncreds.issuerCreateAndStoreClaimDef; import static org.hyperledger.indy.sdk.ledger.Ledger.*; -public class SaveSchemaAndCredDef { +public class WriteSchemaAndCredDef { static void demo() throws Exception { String walletName = "myWallet"; String poolName = "pool"; String stewardSeed = "000000000000000000000000Steward1"; String poolConfig = "{\"genesis_txn\": \"/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis\"}"; + + // 1. System.out.println("\n1. Creating a new local pool ledger configuration that can be used later to connect pool nodes.\n"); Pool.createPoolLedgerConfig(poolName, poolConfig).get(); + // 2 System.out.println("\n2. Open pool ledger and get the pool handle from libindy.\n"); Pool pool = Pool.openPoolLedger(poolName, "{}").get(); + // 3 System.out.println("\n3. Creates a new secure wallet\n"); Wallet.createWallet(poolName, walletName, "default", null, null).get(); + // 4 System.out.println("\n4. Open wallet and get the wallet handle from libindy\n"); Wallet walletHandle = Wallet.openWallet(walletName, null, null).get(); + // 5 System.out.println("\n5. Generating and storing steward DID and Verkey\n"); String did_json = "{\"seed\": \"" + stewardSeed + "\"}"; DidResults.CreateAndStoreMyDidResult stewardResult = Did.createAndStoreMyDid(walletHandle, did_json).get(); @@ -32,6 +38,7 @@ static void demo() throws Exception { System.out.println("Steward DID: " + defaultStewardDid); System.out.println("Steward Verkey: " + stewardResult.getVerkey()); + // 6. System.out.println("\n6. Generating and storing Trust Anchor DID and Verkey\n"); DidResults.CreateAndStoreMyDidResult trustAnchorResult = Did.createAndStoreMyDid(walletHandle, "{}").get(); String trustAnchorDID = trustAnchorResult.getDid(); @@ -39,41 +46,48 @@ static void demo() throws Exception { System.out.println("Trust anchor DID: " + trustAnchorDID); System.out.println("Trust anchor Verkey: " + trustAnchorVerkey); + // 7 System.out.println("\n7. Build NYM request to add Trust Anchor to the ledger\n"); String nymRequest = buildNymRequest(defaultStewardDid, trustAnchorDID, trustAnchorVerkey, null, "TRUST_ANCHOR").get(); System.out.println("NYM request JSON:\n" + nymRequest); + // 8 System.out.println("\n8. Sending the nym request to ledger\n"); String nymResponseJson = signAndSubmitRequest(pool, walletHandle, defaultStewardDid, nymRequest).get(); System.out.println("NYM transaction response:\n" + nymResponseJson); + // 9 System.out.println("\n9. Build the SCHEMA request to add new schema to the ledger as a Steward\n"); String name = "gvt"; String version = "1.0"; String attributes = "[\"age\", \"sex\", \"height\", \"name\"]"; - String schemaDataJSON = "{\"name\":\"" + name + "\",\"version\":\"" + version + "\",\"attr_names\":" + attributes + "}"; + String schemaDataJSON = "{\"name\":\"" + name + "\",\"version\":\"" + version + "\",\"attrNames\":" + attributes + ", id=\"id\", ver=\"1.0\"}"; System.out.println("Schema: " + schemaDataJSON); String schemaRequest = buildSchemaRequest(defaultStewardDid, schemaDataJSON).get(); System.out.println("Schema request:\n" + schemaRequest); + // 10 System.out.println("\n10. Sending the SCHEMA request to the ledger\n"); String schemaResponse = signAndSubmitRequest(pool, walletHandle, defaultStewardDid, schemaRequest).get(); System.out.println("Schema response:\n" + schemaResponse); - System.out.println("\n11. Creating and storing CRED DEF using anoncreds as Trust Anchor, for the given Schema\n"); - String credDefJSON = "{\"seqNo\": 1, \"dest\": \"" + defaultStewardDid + "\", \"data\": " + schemaDataJSON + "}"; - System.out.println("Cred Def JSON:\n" + credDefJSON); - String credDef = issuerCreateAndStoreClaimDef(walletHandle, trustAnchorDID, credDefJSON, "CL", false).get(); - System.out.println("Returned Cred Definition:\n" + credDef); + // 11 + System.out.println("\n11. Creating and storing CLAIM DEFINITION using anoncreds as Trust Anchor, for the given Schema\n"); + String schemaJSON = "{\"seqNo\": 1, \"dest\": \"" + defaultStewardDid + "\", \"data\": " + schemaDataJSON + "}"; + System.out.println("Schema:\n" + schemaJSON); + String claimDef = issuerCreateAndStoreClaimDef(walletHandle, trustAnchorDID, schemaJSON, "CL", false).get(); + System.out.println("Claim Definition:\n" + claimDef); - // Some cleanup code. + // 12 System.out.println("\n12. Close and delete wallet\n"); walletHandle.closeWallet().get(); Wallet.deleteWallet(walletName, null).get(); + // 13 System.out.println("\n13. Close pool\n"); pool.closePoolLedger().get(); + // 14 System.out.println("\n14. Delete pool ledger config\n"); Pool.deletePoolLedgerConfig(poolName).get(); } diff --git a/docs/how-tos/save-schema-and-cred-def/java/WriteSchemaAndCredDef.java b/docs/how-tos/save-schema-and-cred-def/java/WriteSchemaAndCredDef.java deleted file mode 100644 index ab17cfe474..0000000000 --- a/docs/how-tos/save-schema-and-cred-def/java/WriteSchemaAndCredDef.java +++ /dev/null @@ -1,94 +0,0 @@ -import org.hyperledger.indy.sdk.did.Did; -import org.hyperledger.indy.sdk.did.DidResults; -import org.hyperledger.indy.sdk.pool.Pool; -import org.hyperledger.indy.sdk.wallet.Wallet; - -import static org.hyperledger.indy.sdk.anoncreds.Anoncreds.issuerCreateAndStoreClaimDef; -import static org.hyperledger.indy.sdk.ledger.Ledger.*; - -public class WriteSchemaAndCredDef { - static void demo() throws Exception { - String walletName = "myWallet"; - String poolName = "pool"; - String stewardSeed = "000000000000000000000000Steward1"; - String poolConfig = "{\"genesis_txn\": \"/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis\"}"; - - - // 1. - System.out.println("\n1. Creating a new local pool ledger configuration that can be used later to connect pool nodes.\n"); - Pool.createPoolLedgerConfig(poolName, poolConfig).get(); - - // 2 - System.out.println("\n2. Open pool ledger and get the pool handle from libindy.\n"); - Pool pool = Pool.openPoolLedger(poolName, "{}").get(); - - // 3 - System.out.println("\n3. Creates a new secure wallet\n"); - Wallet.createWallet(poolName, walletName, "default", null, null).get(); - - // 4 - System.out.println("\n4. Open wallet and get the wallet handle from libindy\n"); - Wallet walletHandle = Wallet.openWallet(walletName, null, null).get(); - - // 5 - System.out.println("\n5. Generating and storing steward DID and Verkey\n"); - String did_json = "{\"seed\": \"" + stewardSeed + "\"}"; - DidResults.CreateAndStoreMyDidResult stewardResult = Did.createAndStoreMyDid(walletHandle, did_json).get(); - String defaultStewardDid = stewardResult.getDid(); - System.out.println("Steward DID: " + defaultStewardDid); - System.out.println("Steward Verkey: " + stewardResult.getVerkey()); - - // 6. - System.out.println("\n6. Generating and storing Trust Anchor DID and Verkey\n"); - DidResults.CreateAndStoreMyDidResult trustAnchorResult = Did.createAndStoreMyDid(walletHandle, "{}").get(); - String trustAnchorDID = trustAnchorResult.getDid(); - String trustAnchorVerkey = trustAnchorResult.getVerkey(); - System.out.println("Trust anchor DID: " + trustAnchorDID); - System.out.println("Trust anchor Verkey: " + trustAnchorVerkey); - - // 7 - System.out.println("\n7. Build NYM request to add Trust Anchor to the ledger\n"); - String nymRequest = buildNymRequest(defaultStewardDid, trustAnchorDID, trustAnchorVerkey, null, "TRUST_ANCHOR").get(); - System.out.println("NYM request JSON:\n" + nymRequest); - - // 8 - System.out.println("\n8. Sending the nym request to ledger\n"); - String nymResponseJson = signAndSubmitRequest(pool, walletHandle, defaultStewardDid, nymRequest).get(); - System.out.println("NYM transaction response:\n" + nymResponseJson); - - // 9 - System.out.println("\n9. Build the SCHEMA request to add new schema to the ledger as a Steward\n"); - String name = "gvt"; - String version = "1.0"; - String attributes = "[\"age\", \"sex\", \"height\", \"name\"]"; - String schemaDataJSON = "{\"name\":\"" + name + "\",\"version\":\"" + version + "\",\"attrNames\":" + attributes + ", id=\"id\", ver=\"1.0\"}"; - System.out.println("Schema: " + schemaDataJSON); - String schemaRequest = buildSchemaRequest(defaultStewardDid, schemaDataJSON).get(); - System.out.println("Schema request:\n" + schemaRequest); - - // 10 - System.out.println("\n10. Sending the SCHEMA request to the ledger\n"); - String schemaResponse = signAndSubmitRequest(pool, walletHandle, defaultStewardDid, schemaRequest).get(); - System.out.println("Schema response:\n" + schemaResponse); - - // 11 - System.out.println("\n11. Creating and storing CLAIM DEFINITION using anoncreds as Trust Anchor, for the given Schema\n"); - String schemaJSON = "{\"seqNo\": 1, \"dest\": \"" + defaultStewardDid + "\", \"data\": " + schemaDataJSON + "}"; - System.out.println("Schema:\n" + schemaJSON); - String claimDef = issuerCreateAndStoreClaimDef(walletHandle, trustAnchorDID, schemaJSON, "CL", false).get(); - System.out.println("Claim Definition:\n" + claimDef); - - // 12 - System.out.println("\n12. Close and delete wallet\n"); - walletHandle.closeWallet().get(); - Wallet.deleteWallet(walletName, null).get(); - - // 13 - System.out.println("\n13. Close pool\n"); - pool.closePoolLedger().get(); - - // 14 - System.out.println("\n14. Delete pool ledger config\n"); - Pool.deletePoolLedgerConfig(poolName).get(); - } -} diff --git a/docs/how-tos/save-schema-and-cred-def/python/README.md b/docs/how-tos/save-schema-and-cred-def/python/README.md deleted file mode 100644 index 8f48772983..0000000000 --- a/docs/how-tos/save-schema-and-cred-def/python/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# Save a Schema and Credential Definition - -Indy-SDK Developer Walkthrough #4, Python Edition - -[ [Java](../java/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Ensure you have the 64-bit version of Python 3 installed, as the 32-bit version may have problems loading the Indy .dll files. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a Python editor of your -choice and paste the code from [template.py](template.py) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `save_schema_and_cred_def.py` - -This is a very simple app framework into which you'll plug the code you'll be writing. - -Install the required python packages by executing: `$ pip install python3-indy asyncio` - -### Step 2 - -We need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network and how to trust that the nodes it contacts possess -appropriate keys. We also need to create a wallet so the SDK can store -DIDs and the key material we're going to use. Also, we need -to create a trust anchor identity that has privileges to create schemas -and credential definitions. - -All of these steps are similar to those in simpler how-tos, such as -["Write a DID and Query Its Verkey"](../../write-did-and-query-verkey/python/README.md). -We'll get this housekeeping out of -the way in a single step here, rather than dwelling on its details. - -Copy the contents of [step2.py](step2.py) into -`save_schema_and_cred_def.py` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `save_schema_and_cred_def.py`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to create and define a schema. Schemas in indy are very simple -JSON documents that specify their name and version, and that list attributes -that will appear in a credential. Today, they do not describe data type, -recurrence rules, nesting, and other elaborate constructs. There is work -underway to make them fancier; visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) to learn -more. - -A sample schema might look like this: - -```json -{ - "id": "1", - "name": "gvt", - "version": "1.0", - "ver': "1.0", - "attrNames": ["age", "sex", "height", "name"] -} -``` - -Copy the contents of [step3.py](step3.py) into -`save_schema_and_cred_def.py` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `save_schema_and_cred_def.py`. - -Notice how this schema is submitted to the ledger by the steward -identity we created previously. - -### Step 4 - -Next, we create a *credential definition*. This references the schema -that we just added, and announces who is going to be issuing credentials -with that schema (our trust anchor identity, in this case), what type of -signature method they plan to use ("CL" = "Camenisch Lysyanskya", the -default method used for zero-knowledge proofs by indy), how they -plan to handle revocation, and so forth. - -Copy the contents of [step4.py](step4.py) into -`save_schema_and_cred_def.py` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `save_schema_and_cred_def.py``. - -## More experiments - -You might try the ["Issue a Credential"](../../issue-credential/python/README.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/save-schema-and-cred-def/python/write_schema_and_cred_def.py b/docs/how-tos/save-schema-and-cred-def/python/save_schema_and_cred_def.py similarity index 58% rename from docs/how-tos/save-schema-and-cred-def/python/write_schema_and_cred_def.py rename to docs/how-tos/save-schema-and-cred-def/python/save_schema_and_cred_def.py index 04e40a384c..6989ea9854 100644 --- a/docs/how-tos/save-schema-and-cred-def/python/write_schema_and_cred_def.py +++ b/docs/how-tos/save-schema-and-cred-def/python/save_schema_and_cred_def.py @@ -8,7 +8,6 @@ claim definition for the Schema added by Steward. """ - import asyncio import json import pprint @@ -16,11 +15,12 @@ from indy import pool, ledger, wallet, did, anoncreds from indy.error import ErrorCode, IndyError +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -wallet_name = 'wallet' -genesis_file_path = '../indy-sdk/cli/docker_pool_transactions_genesis' +wallet_config = json.dumps({"id": "wallet"}) wallet_credentials = json.dumps({"key": "wallet_key"}) +genesis_file_path = get_pool_genesis_txn_path(pool_name) def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -28,36 +28,36 @@ def print_log(value_color="", value_noncolor=""): ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - async def write_schema_and_cred_def(): try: - await pool.set_protocol_version(2) + await pool.set_protocol_version(PROTOCOL_VERSION) + # 1. - print_log('\n1. Creates a new local pool ledger configuration that is used ' + print_log('\n1. opening a new local pool ledger configuration that will be used ' 'later when connecting to ledger.\n') - pool_config = json.dumps({'genesis_txn': genesis_file_path}) + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) try: - await pool.create_pool_ledger_config(pool_name, pool_config) - except IndyError: - await pool.delete_pool_ledger_config(config_name=pool_name) - await pool.create_pool_ledger_config(pool_name, pool_config) + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. - print_log('\n2. Open pool ledger and get handle from libindy\n') + print_log('\n2. Open pool ledger and get the handle from libindy\n') pool_handle = await pool.open_pool_ledger(config_name=pool_name, config=None) # 3. - print_log('\n3. Creating new secure wallet\n') + print_log('\n3. Creating new secure wallet with the given unique name\n') try: - await wallet.create_wallet(pool_name, wallet_name, None, None, wallet_credentials) - except IndyError: - await wallet.delete_wallet(wallet_name, wallet_credentials) - await wallet.create_wallet(pool_name, wallet_name, None, None, wallet_credentials) + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError as ex: + if ex.error_code == ErrorCode.WalletAlreadyExistsError: + pass # 4. - print_log('\n4. Open wallet and get handle from libindy\n') - wallet_handle = await wallet.open_wallet(wallet_name, None, wallet_credentials) + print_log('\n4. Open wallet and get handle from libindy to use in methods that require wallet access\n') + wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) # 5. print_log('\n5. Generating and storing steward DID and verkey\n') @@ -65,7 +65,7 @@ async def write_schema_and_cred_def(): did_json = json.dumps({'seed': steward_seed}) steward_did, steward_verkey = await did.create_and_store_my_did(wallet_handle, did_json) print_log('Steward DID: ', steward_did) - print_log('Steward Verkey: ', steward_verkey) + print_log('Steward Verkey: ', steward_verkey) # 6. print_log('\n6. Generating and storing trust anchor DID and verkey\n') @@ -93,42 +93,48 @@ async def write_schema_and_cred_def(): pprint.pprint(json.loads(nym_transaction_response)) # 9. - print_log('\n9. Build the SCHEMA request to add new schema to the ledger as a Steward\n') - seq_no = 1 + print_log('\n9. Issuer create Credential Schema\n') schema = { - 'seqNo': seq_no, - 'dest': steward_did, - 'data': { - 'id': '1', - 'name': 'gvt', - 'version': '1.0', - 'ver': '1.0', - 'attrNames': ['age', 'sex', 'height', 'name'] - } + 'name': 'gvt', + 'version': '1.0', + 'attributes': '["age", "sex", "height", "name"]' } - schema_data = schema['data'] - print_log('Schema data: ') - pprint.pprint(schema_data) + issuer_schema_id, issuer_schema_json = await anoncreds.issuer_create_schema(steward_did, + schema['name'], + schema['version'], + schema['attributes']) print_log('Schema: ') - pprint.pprint(schema) - schema_request = await ledger.build_schema_request(steward_did, json.dumps(schema_data)) + pprint.pprint(issuer_schema_json) + + # 10. + print_log('\n10. Build the SCHEMA request to add new schema to the ledger\n') + schema_request = await ledger.build_schema_request(steward_did, issuer_schema_json) print_log('Schema request: ') pprint.pprint(json.loads(schema_request)) - # 10. - print_log('\n10. Sending the SCHEMA request to the ledger\n') - schema_response = await ledger.sign_and_submit_request(pool_handle, wallet_handle, steward_did, schema_request) + # 11. + print_log('\n11. Sending the SCHEMA request to the ledger\n') + schema_response = \ + await ledger.sign_and_submit_request(pool_handle, + wallet_handle, + steward_did, + schema_request) print_log('Schema response:') pprint.pprint(json.loads(schema_response)) - # 11. - print_log('\n11. Creating and storing CRED DEFINITION using anoncreds as Trust Anchor, for the given Schema\n') - cred_def_tag = 'cred_def_tag' + # 12. + print_log('\n12. Creating and storing Credential Definition using anoncreds as Trust Anchor, for the given Schema\n') + cred_def_tag = 'TAG1' cred_def_type = 'CL' cred_def_config = json.dumps({"support_revocation": False}) - (cred_def_id, cred_def_json) = await anoncreds.issuer_create_and_store_credential_def(wallet_handle, trust_anchor_did, json.dumps(schema_data), - cred_def_tag, cred_def_type, cred_def_config) + (cred_def_id, cred_def_json) = \ + await anoncreds.issuer_create_and_store_credential_def(wallet_handle, + trust_anchor_did, + issuer_schema_json, + cred_def_tag, + cred_def_type, + cred_def_config) print_log('Credential definition: ') pprint.pprint(json.loads(cred_def_json)) @@ -139,7 +145,7 @@ async def write_schema_and_cred_def(): # 13. print_log('\n13. Deleting created wallet\n') - await wallet.delete_wallet(wallet_name, wallet_credentials) + await wallet.delete_wallet(wallet_config, wallet_credentials) # 14. print_log('\n14. Deleting pool ledger config\n') @@ -148,7 +154,6 @@ async def write_schema_and_cred_def(): except IndyError as e: print('Error occurred: %s' % e) - def main(): loop = asyncio.get_event_loop() loop.run_until_complete(write_schema_and_cred_def()) diff --git a/docs/how-tos/save-schema-and-cred-def/python/template.py b/docs/how-tos/save-schema-and-cred-def/python/template.py index f3c6073dfb..a34430beab 100644 --- a/docs/how-tos/save-schema-and-cred-def/python/template.py +++ b/docs/how-tos/save-schema-and-cred-def/python/template.py @@ -7,21 +7,20 @@ Once that succeeds, Trust Anchor uses anonymous credentials to issue and store claim definition for the Schema added by Steward. """ - - import asyncio import json import pprint from indy import pool, ledger, wallet, did, anoncreds -from indy.error import IndyError +from indy.error import ErrorCode, IndyError +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' +genesis_file_path = get_pool_genesis_txn_path(pool_name) + wallet_config = json.dumps({"id": "wallet"}) wallet_credentials = json.dumps({"key": "wallet_key"}) -PROTOCOL_VERSION=2 def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -29,10 +28,10 @@ def print_log(value_color="", value_noncolor=""): ENDC = '\033[0m' print(HEADER + value_color + ENDC + str(value_noncolor)) - async def write_schema_and_cred_def(): try: await pool.set_protocol_version(PROTOCOL_VERSION) + # Step 2 code goes here. # Step 3 code goes here. @@ -42,13 +41,11 @@ async def write_schema_and_cred_def(): except IndyError as e: print('Error occurred: %s' % e) - def main(): loop = asyncio.get_event_loop() loop.run_until_complete(write_schema_and_cred_def()) loop.close() - if __name__ == '__main__': main() diff --git a/docs/how-tos/save-schema-and-cred-def/python/utils.py b/docs/how-tos/save-schema-and-cred-def/python/utils.py new file mode 100644 index 0000000000..a9bdd66d86 --- /dev/null +++ b/docs/how-tos/save-schema-and-cred-def/python/utils.py @@ -0,0 +1,31 @@ +from os import environ +from pathlib import Path +from tempfile import gettempdir + +PROTOCOL_VERSION = 2 + +def get_pool_genesis_txn_path(pool_name): + path_temp = Path(gettempdir()).joinpath("indy") + path = path_temp.joinpath("{}.txn".format(pool_name)) + save_pool_genesis_txn_file(path) + return path + +def pool_genesis_txn_data(): + pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") + + return "\n".join([ + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( + pool_ip, pool_ip) + ]) + +def save_pool_genesis_txn_file(path): + data = pool_genesis_txn_data() + path.parent.mkdir(parents=True, exist_ok=True) + with open(str(path), "w+") as f: + f.writelines(data) diff --git a/docs/how-tos/save-schema-and-cred-def/rust/README.md b/docs/how-tos/save-schema-and-cred-def/rust/README.md deleted file mode 100644 index c53f1b8c5c..0000000000 --- a/docs/how-tos/save-schema-and-cred-def/rust/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Save a Schema and Credential Definition - -Indy-SDK Developer Walkthrough #4, Rust Edition - -[ [Python](../python/README.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Java](../java/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a rust editor of your -choice and paste the code from [template.rs](template.rs) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `write-schema-and-cred-def.rs` - -This is a simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -We need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network and how to trust that the nodes it contacts possess -appropriate keys. We also need to create a wallet so the SDK can store -DIDs and the key material we're going to use. Also, we need -to create a trust anchor identity that has privileges to create schemas -and credential definitions. - -All of these steps are similar to those in simpler how-tos, such as -["Write a DID and Query Its Verkey"](../../write-did-and-query-verkey/rust/README.md). -We'll get this housekeeping out of -the way in a single step here, rather than dwelling on its details. - -Copy the contents of [step2.rs](step2.rs) into -`write-schema-and-cred-def.rs` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `write-schema-and-cred-def.rs`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to create and define a schema. Schemas in indy are very simple -JSON documents that specify their name and version, and that list attributes -that will appear in a credential. Today, they do not describe data type, -recurrence rules, nesting, and other elaborate constructs. There is work -underway to make them fancier; visit -[#indy-sdk on Rocket.Chat](https://chat.hyperledger.org/channel/indy-sdk) to learn -more. - -Copy the contents of [step3.rs](step3.rs) into -`write-schema-and-cred-def.rs` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `write-schema-and-cred-def.rs`. - -Notice how this schema is submitted to the ledger by the steward -identity we created previously. - -### Step 4 - -Next, we create a *credential definition*. This references the schema -that we just added, and announces who is going to be issuing credentials -with that schema (our trust anchor identity, in this case), what type of -signature method they plan to use ("CL" = "Camenisch Lysyanskya", the -default method used for zero-knowledge proofs by indy), how they -plan to handle revocation, and so forth. - -Copy the contents of [step4.rs](step4.rs) into -`write-schema-and-cred-def.rs` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `write-schema-and-cred-def.rs`. - -### Step 5 - -Run the [finished code](write-schema-and-cred-def.rs) and observe the whole sequence. - -## More experiments - -You might try the ["Issue a Credential"](../../issue-cred/../not-yet-written.md) -how-to, which can be done in only one step once you complete this one. diff --git a/docs/how-tos/send-secure-msg/README.md b/docs/how-tos/send-secure-msg/README.md index 159349b35d..8c3d6bfbfe 100644 --- a/docs/how-tos/send-secure-msg/README.md +++ b/docs/how-tos/send-secure-msg/README.md @@ -5,9 +5,162 @@ features to send and receive a secure message. Messaging primitives are important in many interactions, although they are not explicitly required in the other how-tos. -[ [Python](python/README.md) | - [Java](../not-yet-written.md) | - [.NET](../not-yet-written.md) | - [Node.js](../not-yet-written.md) | - [Objective C](../not-yet-written.md) | - [Rust](rust/README.md) ] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `send_secure_msg.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `send_secure_msg.py`, for nodejs: `send_secure_msg.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](../not-yet-written.md) | [Rust template](rust/src/template.rs)] + +This is a very simple app that allows you to act as a sender or a receiver +of a message. Take a minute to understand its basic structure: it runs a +loop, asking you for input. + +It recognizes three commands: `read`, `prep`, and `quit`. + +### Step 2 + +Run the app on your workstation. +You should see some simple text output. Try a few commands. + +Type `quit` when you're done. + +### Step 3 + +Now we get to begin adding interesting features. + +The first thing we need to do is give the app the DIDs and the keys it +needs to communicate. +Open the correspondent `step3` file below in a text editor and copy +its contents into `send_secure_msg` file created in the first step, replacing the stub of +the `init()` function from your template. Save it and study the changes. + +[ [Python step3](python/step3.py) | [Rust step3](rust/src/step3.rs)] + +First `init()` asks the user for their name. It then invokes indy-sdk's +`create_wallet()` function to make a wallet associated with a fictional +pool (ledger). It records the wallet handle. Once the wallet has been +created, it opens the wallet and asks indy-sdk to generate a DID and a +public verkey + private signing key pair, storing all that information +in the wallet. + +Finally, `init()` asks the user to provide the DID and verkey of the +other party that will be exchanging messages, and it returns a tuple of +all the information it's accumulated, except for the secret signing key +that remains in the wallet. + +### Step 4 + +In your development VM, run the app again. + +You should be prompted for a name. Say "Alice". Then the app should show you the DID and verkey it generated, and ask you for the DID and verkey of the other party. + +Press **CTRL+C** to kill the app. + +``` +Who are you? Alice +wallet = 1 +my_did and verkey = ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf +Other party's DID and verkey? ^C +``` + +We will eventually run this app twice--in one window as Alice, and in another +window as Bob. Each instance of the app will generate its own keys and +you can use copy/paste to share them with the other window. + +### Step 5 + +Now we need to add secure encryption using indy crypto's [`auth_crypt()`](https://github.com/hyperledger/indy-sdk/blob/eb7ea544ae8616883c6011a57d40f1b14cd5afeb/libindy/src/api/crypto.rs#L328) primitive. + +Copy the contents of the correspondent `step5` file below into your `send_secure_msg` file, replacing the stub of the `prep()` function on it. Save the file and study the changes. + +[ [Python step5](python/step5.py) | [Rust step5](rust/src/step5.rs)] + +The `prep()` function is designed to be called with a string argument entered +on the command line. + +For example, when the user types `prep Hello, world`, the `msg` parameter of `prep()` receives the value `"Hello, world"`. Prep encode and saves this message into a binary file to be read later in the next step, simulating a communication channel between two agents. Then it calls `auth_crypt()` to convert those bytes into a version that is encrypted especially for the private channel between two identities. The receiver will know that the sender created the message, that only the receiver can interpret it, and that it has not been tampered with. + +If you like, try running the updated app in your development VM again. When +prompted for the DID and verkey of the other party, just paste values produced +during a previous run, separated by space (e.g., `ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf`) and press enter and then try typing `prep Hello, world` to create the encrypted `message.dat` file. + +Press **CTRL+C** to kill the app. + +### Step 6 + +The final feature that our app needs is the ability to read encrypted data. +Copy the contents of the correspondent `step6` file into your `send_secure_msg` file, replacing the stub of the `prep()` function on it. Then save and study the changes. + +[ [Python step6](python/step6.py) | [Rust step6](rust/src/step6.rs)] + +The read function is very simple. It just copies the content of the +`message.dat` file from disk into memory and then calls indy crypto's +`auth_decrypt()` function on the byte array. The output is a tuple that +contains the verkey of the sender and the decrypted value if the +message was encrypted for the key of the recipient, or an exception if +not. + +### Step 7 + +Now let's put this all together. Try to run the completed demo and observe the whole sequence. + +[ [Python complete](python/send_secure_msg.py) | [Rust complete](rust/src/send-secure-msg.rs)] + +In your indy development VM, create two shells (command prompts). Both should have the location of your code as their current working directory. Run one instance of your `send_secure_msg` script in the first window, and another in the second window. + +In the first window, when prompted for your name, say "Alice". In the +second window, say "Bob". + +In the Alice window, you should now see a line that specifies a DID and +verkey for Alice. It should be something like this: + +``` +my_did and verkey = ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf +``` + +Copy these two strings (everything after `"my_did and verkey = "`) to your +clipboard. + +Navigate to the Bob window. Bob's window should have a different did and verkey displayed, and should be prompting for Alice's info. + +Paste Alice's information into Bob's window and press Enter. + +Copy Bob's information and paste it into Alice's window. + +**Note:** The process of copying and pasting between two windows is a simplistic way to model more sophisticated onboarding workflows in the Sovrin ecosystem. Within the Sovrin ecosystem parties receive a trusted mutual introduction, or where one scans a QR code from the other, or where they exchange information over the phone or face to face. + +Both windows should now be displaying a prompt again. + +In the Alice window, type `prep Hi, Bob.` and press **Enter**. + +In the Bob window, type `read` and press **Enter**. + +Bob's window should display a tuple that it decrypts from Alice; the first +element in the tuple is Alice's verkey (check its value to confirm); the +second is the text, `"Hi, Bob."`. Alice has sent Bob an encrypted message. + +## More Experiments + +Try modifying `message.dat` with a binary editor. This simulates tampering by +an eavesdropper. When Bob attempts to decrypt the message, decryption should +fail. + +Try transmitting the encrypted message over a different channel. For example, +after Alice writes the message, email `message.dat` or copy it over the network +or send it as an attachment via Skype or Slack. Then copy the received package +into the correct folder with the name `message.dat` and ask Bob to read it. + +Try modifying the script so it uses `anon_crypt()` instead of `auth_crypt()` and +`anon_decrypt()` instead of `auth_decrypt()`. Notice the outcome. diff --git a/docs/how-tos/send-secure-msg/python/README.md b/docs/how-tos/send-secure-msg/python/README.md deleted file mode 100644 index 3935ae66ee..0000000000 --- a/docs/how-tos/send-secure-msg/python/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Send a Secure Message -Indy-SDK Developer Walkthrough #3, Python Edition - -[ [Java](../../not-yet-written.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) ] - - -## Prerequisites - -Setup your workstation and indy development virtual machine. See [prerequisites](../../prerequisites.md). - -## Steps - -### Step 1 - -In your normal workstation OS (not the VM), open a python editor of your -choice and paste the code from [template.py](template.py) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `msgme.py` - -This is a very simple app that allows you to act as a sender or a receiver -of a message. Take a minute to understand its basic structure: it runs a -loop, asking you for input. - -It recognizes three commands: `read`, `prep`, and `quit`. - -### Step 2 - -Run the app on your workstation if you have python3 installed there, or -in your indy development VM, otherwise: `python3 msgme.py`. - -You should see some simple text output. Try a few commands. - -Type `quit` when you're done. - -### Step 3 - -Now we get to begin adding interesting features. - -The first thing we need to do is give the app the DIDs and the keys it -needs to communicate. Open [step3.py](step3.py) in a text editor and copy -its contents into `msgme.py`, replacing the stub of -the `init()` function from your template. - -We will also have to import some dependencies, since this function uses -indy and thus depends on the SDK. Go to the top of `msgme.py` and add -a new import statement: - - ```python -from indy import crypto, did, wallet -``` - -Save the updated version of `msgme.py`. Now take a minute and study the changes. - -First `init()` asks the user for their name. It then invokes indy-sdk's -`create_wallet()` function to make a wallet associated with a fictional -pool (ledger). It records the wallet handle. Once the wallet has been -created, it opens the wallet and asks indy-sdk to generate a DID and a -public verkey + private signing key pair, storing all that information -in the wallet. - -Finally, `init()` asks the user to provide the DID and verkey of the -other party that will be exchanging messages, and it returns a tuple of -all the information it's accumulated, except for the secret signing key -that remains in the wallet. - -### Step 4 - -In your development VM, run the app again. - -You should be prompted for a name. Say "Alice". Then the app should show you the DID and verkey it generated, and ask you for the DID and verkey of the other party. - -Press **CTRL+C** to kill the app. - -``` -vagrant@development:/src/indy-sdk/samples/python/src$ python3 msgme1.py -Who are you? Alice -wallet = 1 -my_did and verkey = ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf -Other party's DID and verkey? ^C -``` - -We will eventually run this app twice--in one window as Alice, and in another -window as Bob. Each instance of the app will generate its own keys and -you can use copy/paste to share them with the other window. - -### Step 5 - -Now we need to add secure encryption using indy crypto's [`auth_crypt()`](https://github.com/hyperledger/indy-sdk/blob/master/libindy/src/api/crypto.rs#L272) -primitive. - -Copy the contents of [step5.py](step5.py) into `msgme.py`, replacing the stub of -the `prep()` function from your template. - -Save the updated version of `msgme.py`. Now take a minute and study the changes. - -The `prep()` function is designed to be called with a string argument entered -on the command line. - -For example, when the user types `prep Hello, world`, the `msg` parameter of `prep()` receives the value `"Hello, world"`. Prep saves this message into a text file (so you can inspect it--not because it needs to do any file I/O). It then turns around and reads the bytes it has just written, and calls `auth_crypt()` to convert those bytes into a version that is encrypted especially for the private channel between two identities. The receiver will know that the sender created the message, that only the receiver can interpret it, and that it has not been tampered with. - -If you like, try running the updated app in your development VM again. When -prompted for the DID and verkey of the other party, just paste values produced -during a previous run (e.g., `ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf`) and press enter. Then try typing `prep Hello, world` and inspecting the `input.txt` and `encrypted.dat` files that are created. - -Press **CTRL+C** to kill the app. - -### Step 6 - -The final feature that our app needs is the ability to read encrypted data. -Copy the contents of [step6.py](step6.py) into `msgme.py`, replacing the stub of the `prep()` -function from your template. - -Save the updated version of `msgme.py`. Now take a minute and study the -changes. - -The read function is very simple. It just copies the content of the -`encrypted.dat` file from disk into memory and then calls indy crypto's -`auth_decrypt()` function on the byte array. The output is a tuple that -contains the verkey of the sender and the decrypted value if the -message was encrypted for the key of the recipient--or an exception if -not. - -### Step 7 - -Now let's put this all together. - -In your indy development VM, create two shells (command prompts). Both should have the location of your code as their current working directory. Start one copy of your scripts in the first window (`python3 msgme.py`), and another copy in the second window. - -In the first window, when prompted for your name, say "Alice". In the -second window, say "Bob". - -In the Alice window, you should now see a line that specifies a DID and -verkey for Alice. It should look something like this: - -``` -my_did and verkey = ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf -``` - -Copy these two strings (everything after `"my_did and verkey = "`) to your -clipboard. - -Navigate to the Bob window. Bob's window should have a different did and verkey displayed, and should be prompting for Alice's info. - -Paste Alice's information into Bob's window and press Enter. - -Copy Bob's information and paste it into Alice's window. - -**Note:** The process of copying and pasting between two windows is a simplistic way to model more sophisticated onboarding workflows in the Sovrin ecosystem. Within the Sovrin ecosystem parties receive a trusted mutual introduction, or where one scans a QR code from the other, or where they exchange information over the phone or face to face. - -Both windows should now be displaying a prompt again. - -In the Alice window, type `prep Hi, Bob.` and press **Enter**. - -In the Bob window, type `read` and press **Enter**. - -Bob's window should display a tuple that it decrypts from Alice; the first -element in the tuple is Alice's verkey (check its value to confirm); the -second is the text, `"Hi, Bob."`. Alice has sent Bob an encrypted message. - -## More Experiments - -Try modifying `encrypted.dat` with a binary editor. This simulates tampering by -an eavesdropper. When Bob attempts to decrypt the message, decryption should -fail. - -Try transmitting the encrypted message over a different channel. For example, -after Alice writes the message, email `encrypted.dat` or copy it over the network -or send it as an attachment via Skype or Slack. Then copy the received package -into the correct folder with the name `encrypted.dat` and ask Bob to read it. - -Try modifying the script so it uses `anon_crypt()` instead of `auth_crypt()` and -`anon_decrypt()` instead of `auth_decrypt()`. Notice the outcome. diff --git a/docs/how-tos/send-secure-msg/python/send_secure_msg.py b/docs/how-tos/send-secure-msg/python/send_secure_msg.py new file mode 100644 index 0000000000..3fcbbba961 --- /dev/null +++ b/docs/how-tos/send-secure-msg/python/send_secure_msg.py @@ -0,0 +1,64 @@ +import asyncio +import time +import re + +from indy import crypto, did, wallet + +async def prep(wallet_handle, my_vk, their_vk, msg): + msg = bytes(msg, "utf-8") + encrypted = await crypto.auth_crypt(wallet_handle, my_vk, their_vk, msg) + # encrypted = await crypto.anon_crypt(their_vk, msg) + print('encrypted = %s' % repr(encrypted)) + with open('message.dat', 'wb') as f: + f.write(encrypted) + print('prepping %s' % msg) + +async def init(): + me = input('Who are you? ').strip() + wallet_config = '{"id": "%s-wallet"}' % me + wallet_credentials = '{"key": "%s-wallet-key"}' % me + + # 1. Create Wallet and Get Wallet Handle + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except: + pass + wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) + print('wallet = %s' % wallet_handle) + + (my_did, my_vk) = await did.create_and_store_my_did(wallet_handle, "{}") + print('my_did and verkey = %s %s' % (my_did, my_vk)) + + their = input("Other party's DID and verkey? ").strip().split(' ') + return wallet_handle, my_did, my_vk, their[0], their[1] + +async def read(wallet_handle, my_vk): + with open('message.dat', 'rb') as f: + encrypted = f.read() + decrypted = await crypto.auth_decrypt(wallet_handle, my_vk, encrypted) + # decrypted = await crypto.anon_decrypt(wallet_handle, my_vk, encrypted) + print(decrypted) + +async def demo(): + wallet_handle, my_did, my_vk, their_did, their_vk = await init() + + while True: + argv = input('> ').strip().split(' ') + cmd = argv[0].lower() + rest = ' '.join(argv[1:]) + if re.match(cmd, 'prep'): + await prep(wallet_handle, my_vk, their_vk, rest) + elif re.match(cmd, 'read'): + await read(wallet_handle, my_vk) + elif re.match(cmd, 'quit'): + break + else: + print('Huh?') + +if __name__ == '__main__': + try: + loop = asyncio.get_event_loop() + loop.run_until_complete(demo()) + time.sleep(1) # waiting for libindy thread complete + except KeyboardInterrupt: + print('') diff --git a/docs/how-tos/send-secure-msg/python/step5.py b/docs/how-tos/send-secure-msg/python/step5.py index 08ffdea7dc..2c3a7529e8 100644 --- a/docs/how-tos/send-secure-msg/python/step5.py +++ b/docs/how-tos/send-secure-msg/python/step5.py @@ -1,11 +1,8 @@ async def prep(wallet_handle, my_vk, their_vk, msg): - with open('plaintext.txt', 'w') as f: - f.write(msg) - with open('plaintext.txt', 'rb') as f: - msg = f.read() - encrypted = await crypto.anon_crypt(wallet_handle, my_vk, their_vk, msg) + msg = bytes(msg, "utf-8") + encrypted = await crypto.auth_crypt(wallet_handle, my_vk, their_vk, msg) # encrypted = await crypto.anon_crypt(their_vk, msg) print('encrypted = %s' % repr(encrypted)) - with open('encrypted.dat', 'wb') as f: - f.write(bytes(encrypted)) - print('prepping %s' % msg) + with open('message.dat', 'wb') as f: + f.write(encrypted) + print('prepping %s' % msg) \ No newline at end of file diff --git a/docs/how-tos/send-secure-msg/python/step6.py b/docs/how-tos/send-secure-msg/python/step6.py index 35c73525c6..08ebac4c80 100644 --- a/docs/how-tos/send-secure-msg/python/step6.py +++ b/docs/how-tos/send-secure-msg/python/step6.py @@ -1,5 +1,5 @@ async def read(wallet_handle, my_vk): - with open('encrypted.dat', 'rb') as f: + with open('message.dat', 'rb') as f: encrypted = f.read() decrypted = await crypto.auth_decrypt(wallet_handle, my_vk, encrypted) # decrypted = await crypto.anon_decrypt(wallet_handle, my_vk, encrypted) diff --git a/docs/how-tos/send-secure-msg/python/template.py b/docs/how-tos/send-secure-msg/python/template.py index cae0bb0521..f9e8d91f6a 100644 --- a/docs/how-tos/send-secure-msg/python/template.py +++ b/docs/how-tos/send-secure-msg/python/template.py @@ -2,6 +2,9 @@ import time import re +# Not used here, but will be required for the next steps +from indy import crypto, did, wallet + # Step 5 code goes here, replacing the prep() stub. async def prep(wallet_handle, my_vk, their_vk, msg): print('prepping %s' % msg) diff --git a/docs/how-tos/send-secure-msg/rust/README.md b/docs/how-tos/send-secure-msg/rust/README.md deleted file mode 100644 index 1cad7320f6..0000000000 --- a/docs/how-tos/send-secure-msg/rust/README.md +++ /dev/null @@ -1,148 +0,0 @@ -# Send a Secure Message -Indy-SDK Developer Walkthrough #3, Rust Edition - -[ [Java](../../not-yet-written.md) | [.NET](../../not-yet-written.md) | [Node.js](../../not-yet-written.md) | [Objective C](../../not-yet-written.md) | [Python](../python/README.md) ] - - -## Prerequisites - -Setup your workstation and indy development virtual machine. See [prerequisites](../../prerequisites.md). - -## Steps - -### Step 1 - -In your normal workstation OS (not the VM), open a rust editor of your -choice and paste the code from [template.rs](template.rs) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `send-secure-msg.rs` - -This is a very simple app that allows you to act as a sender or a receiver -of a message. Take a minute to understand its basic structure: it runs a -loop, asking you for input. - -It recognizes three commands: `read`, `prep`, and `quit`. - -### Step 2 - -Run the app on your workstation. -You should see some simple text output. Try a few commands. - -Type `quit` when you're done. - -### Step 3 - -Now we get to begin adding interesting features. - -The first thing we need to do is give the app the DIDs and the keys it -needs to communicate. Open [step3.rs](step3.rs) in a text editor and copy -its contents into `send-secure-msg.rs`, next replace the stub of -the `init()` function on `let (wallet_handle, verkey, other_verkey) = init();`. - -Save the updated version of `send-secure-msg.rs`. Now take a minute and study the changes. - -First `init()` asks the user for their name. It then invokes indy-sdk's -`create_wallet()` function to make a wallet associated with a fictional -pool (ledger). It records the wallet handle. Once the wallet has been -created, it opens the wallet and asks indy-sdk to generate a DID and a -public verkey + private signing key pair, storing all that information -in the wallet. - -Finally, `init()` asks the user to provide the DID and verkey of the -other party that will be exchanging messages, and it returns a tuple of -all the information it's accumulated, except for the secret signing key -that remains in the wallet. - -### Step 4 - -Run the app again. - -You should be prompted for a name. Say "Alice". Then the app should show you the DID and verkey it generated, and ask you for the DID and verkey of the other party. - -Press **CTRL+C** to kill the app. - -``` -cargo run -Who are you? Alice -My DID and Verkey: ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf -Other party's DID and Verkey? ^C -``` - -We will eventually run this app twice--in one window as Alice, and in another -window as Bob. Each instance of the app will generate its own keys and -you can use copy/paste to share them with the other window. - -### Step 5 - -Now we need to add secure encryption using indy crypto's [`auth_crypt()`](https://github.com/hyperledger/indy-sdk/blob/master/libindy/src/api/crypto.rs#L272) -primitive. - -Copy the contents of [step5.rs](step5.rs) into `send-secure-msg.rs` and replace the stub of -the `prep()` function on `prep(wallet_handle, &verkey, &other_verkey);`. - -Save the updated version of `send-secure-msg.rs`. Now take a minute and study the changes. - -The `prep()` function is designed to be called with a string argument entered -on the command line. - -For example, when the user types `prep Hello, world`, the `msg` parameter of `prep()` receives the value `"Hello, world"`. Prep saves this message into a text file (so you can inspect it--not because it needs to do any file I/O). It then turns around and reads the bytes it has just written, and calls `auth_crypt()` to convert those bytes into a version that is encrypted especially for the private channel between two identities. The receiver will know that the sender created the message, that only the receiver can interpret it, and that it has not been tampered with. - -If you like, try running the updated app in your development VM again. When -prompted for the DID and verkey of the other party, just paste values produced -during a previous run (e.g., `ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf`) and press enter. Then try typing `prep Hello, world` and inspecting the `message.txt` that are created. - -Press **CTRL+C** to kill the app. - -### Step 6 - -The final feature that our app needs is the ability to read encrypted data. -Copy the contents of [step6.rs](step6.rs) into `send-secure-msg.rs` and replace the stub of the `read()` -function on `read(wallet_handle, &verkey);`. - -Save the updated version of `send-secure-msg.rs`. Now take a minute and study the -changes. - -The read function is very simple. It just copies the content of the -`message.txt` file from disk into memory and then calls indy crypto's -`auth_decrypt()` function on the byte array. The output is a tuple that -contains the verkey of the sender and the decrypted value if the -message was encrypted for the key of the recipient--or an exception if -not. - -### Step 7 - -Now let's put this all together. - -In your indy development VM, create two shells (command prompts). Both should have the location of your code as their current working directory. Start one copy of your scripts in the first window (`cargo run`), and another copy in the second window. - -In the first window, when prompted for your name, say "Alice". In the -second window, say "Bob". - -In the Alice window, you should now see a line that specifies a DID and -verkey for Alice. It should look something like this: - -``` -My DID and Verkey: ChST7uE2KH3hscqycs5mVf 7NmnhUTnqqh1xydTSZNZCp1wTt3HAua7gA5T2odzLSTf -``` - -Copy these two strings (everything after `"My DID and Verkey: "`) to your -clipboard. - -Navigate to the Bob window. Bob's window should have a different did and verkey displayed, and should be prompting for Alice's info. - -Paste Alice's information into Bob's window and press Enter. - -Copy Bob's information and paste it into Alice's window. - -**Note:** The process of copying and pasting between two windows is a simplistic way to model more sophisticated onboarding workflows in the Sovrin ecosystem. Within the Sovrin ecosystem parties receive a trusted mutual introduction, or where one scans a QR code from the other, or where they exchange information over the phone or face to face. - -Both windows should now be displaying a prompt again. - -In the Alice window, type `prep Hi, Bob.` and press **Enter**. - -In the Bob window, type `read` and press **Enter**. - -Bob's window should display a tuple that it decrypts from Alice; the first -element in the tuple is Alice's verkey (check its value to confirm); the -second is the text, `"Hi, Bob."`. Alice has sent Bob an encrypted message. \ No newline at end of file diff --git a/docs/how-tos/trouble-shooting.md b/docs/how-tos/trouble-shooting.md new file mode 100644 index 0000000000..a6a099cf7a --- /dev/null +++ b/docs/how-tos/trouble-shooting.md @@ -0,0 +1,36 @@ +# Common errors + +If one of the following possible errors happened to you, try to apply the solutions listed below. + +Note that the errors presented here are language agnostic and as a matter of illustration, the example is given in python, but similar logic can be applied for the other languages. + +1. Error `PoolLedgerConfigAlreadyExistsError`. + + Delete config before creating: + ```python + try: + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError: + await pool.delete_pool_ledger_config(config_name=pool_name) + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + ``` + +2. Error `WalletAlreadyExistsError`. + + Delete wallet before creating: + ```python + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError: + await wallet.delete_wallet(wallet_name, wallet_credentials) + await wallet.create_wallet(wallet_config, wallet_credentials) + ``` + +3. Error `CommonIOError`. + + Make sure that you have set `genesis_file_path` to point to your `indy-sdk/cli/docker_pool_transactions_genesis`. + +4. Error `PoolLedgerTimeout`. + + Make sure that the pool of local nodes in Docker is running on the same ip/ports as + in the `docker_pool_transactions_genesis` (for further details see [How to start local nodes pool with docker](https://github.com/hyperledger/indy-sdk/blob/master/README.md#how-to-start-local-nodes-pool-with-docker)) diff --git a/docs/how-tos/write-did-and-query-verkey/README.md b/docs/how-tos/write-did-and-query-verkey/README.md index 9147d28f89..a6a72a11fb 100644 --- a/docs/how-tos/write-did-and-query-verkey/README.md +++ b/docs/how-tos/write-did-and-query-verkey/README.md @@ -4,4 +4,119 @@ This is the most basic operation in indy; it establishes a new DID and then proves that information about it can be queried from the ledger. A good step after this how-to would be ["Rotate Key"](../rotate-key/README.md). -[ [Python](python/README.md) | [Java](java/README.md) | [.NET](cs/README.md) | [Node.js](nodejs/README.md) | [Objective C](../not-yet-written.md) | [Rust](rust/README.md)] +In case of troubles running the how-to, please read the [trouble shooting](../trouble-shooting.md) section. + +## Prerequisites + +Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../prerequisites.md). + +## Steps + +### Step 1 + +In your normal workstation operating system (not the VM), open a text editor of your +choice and paste the *template* code of one of the available in the list bellow into +a new file and saved it as `write_did.EXT`, replacing *EXT* with the proper file +extension (e.g for python: `write_did.py`, for nodejs: `write_did.js`, and so on). +We will be modifying this code in later steps. + +[ [Python template](python/template.py) | [Java template](java/template.java) | [.NET template](cs/Template.cs) | [Node.js template](nodejs/template.js) | [Rust template](rust/src/template.rs)] + +This is a very simple app framework into which you'll plug the code you'll be writing. + +### Step 2 + +Now we need to give the SDK some context that it will need +to deal with an indy ledger. This requires us to point the SDK at some +*genesis transactions* that tell the SDK how to contact the ledger on +the network, and how to trust that the nodes it contacts possess +appropriate keys. + +We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key +material generated during the tutorial. + +![more info on wallets](wallet-slide.png) + +Copy the contents of the correspondent *step2* file below into your `write_did` file +instead of the `Step 2 code goes here` placeholder comment, and save it. + +[ [Python step2](python/step2.py) | [Java step2](java/step2.java) | [.NET step2](../not-yet-written.md) | [Node.js step2](nodejs/step2.js) | [Rust step2](rust/src/step2.rs)] + +Study the changes. Scaffolding code like this is likely to appear in anything +that uses indy. + +### Step 3 + +Now we need to put some DIDs and keys in our identity wallet. Copy the contents of +the correspondent *step3* file below into your `write_did` file instead of the `Step 3 code goes here` placeholder comment. + +[ [Python step3](python/step3.py) | [Java step3](java/step3.java) | [.NET step3](../not-yet-written.md) | [Node.js step3](nodejs/step3.js) | [Rust step3](rust/src/step3.rs)] + +Study the changes. + +A few operations in indy [can only be done by identities (DIDs) with +special roles](https://github.com/hyperledger/indy-node/blob/master/docs/source/auth_rules.md). For example, a DID that is a *steward* can add a node (the one +they own) to the validator pool, and can create DIDs with a *trust anchor* +role. A trust anchor DID can add arbitrary DIDs to the ledger. + +Here, we are populating our identity wallet with DID+keypair material for +one steward identity and one trust anchor identity. The steward identity is +a bootstrapping step, whereas the trust anchor DID is the one we will query +later. + +Notice that the steward DID is created with a seed, but the trust anchor DID is not. +This is because the steward DID and its verkey is already in the ledger; +they were part of the genesis transactions we told the SDK to start with +in the previous step. But we have to also put the DID, verkey, and *private* +signing key (which the ledger doesn't know) into our wallet, so we can use +the signing key to submit an acceptably signed transaction to the ledger. +We will use this steward's signing key to create our *next* DID--the +one for our trust anchor, which is truly new. This is why we use a hard-coded seed +when creating the steward DID--it guarantees that the same DID and key +material are created that the genesis transactions expect. In a production indy pool +such as the Sovrin "live" network, the bootstrapping steward identities +would not have known the seeds. + +### Step 4 + +Now that preparations are complete, we can finally write the DID and verkey +for our trust anchor identity to the ledger. + +Copy the contents of *step4* file below into your `write_did` file instead of +the `Step 4 code goes here` placeholder comment. + +[ [Python step4](python/step4.py) | [Java step4](java/step4.java) | [.NET step4](../not-yet-written.md) | [Node.js step4](nodejs/step4.js) | [Rust step4](rust/src/step4.rs)] + +### Step 5 + +Once we have an identity on the ledger, we can query it. + +Copy the contents of *step5* file below into `write_did` file instead of +the `Step 5 code goes here` placeholder comment. + +[ [Python step5](python/step5.py) | [Java step5](java/step5.java) | [.NET step5](../not-yet-written.md) | [Node.js step5](nodejs/step5.js) | [Rust step5](rust/src/step5.rs)] + +Only a handful of lines of code matter to our goal here; the rest of +this block is comments and boilerplate cleanup **(which you should not omit!)**. +You should see similarities between the way this query "transaction" and +the preceding write transaction are bundled, sent, and awaited. + +### Step 6 + +Run the completed demo and observe the whole sequence. + +[ [Python complete](python/write_did_and_query_verkey.py) | [Java complete](java/WriteDIDAndQueryVerkey.java) | [.NET complete](cs/WriteDIDAndQueryVerkey.cs) | [Node.js complete](nodejs/writeDidAndQueryVerkey.js) | [Rust complete](rust/src/write-did-and-query-verkey.rs)] + +## More experiments + +Most of the code in this how-to exists to satisfy some preconditions. +Now that you have a trust anchor identity, you can write or query +any number of additional identities to the ledger, with just a handful of +lines of code. Try creating some. + +You might try the ["Rotate a Key"](../rotate-key/README.md) +how-to, which can be done in only one step one you complete this one. + +You could also try to create a new steward identity without a seed, or +with a different seed, and see what kind of error you get. Only identities +with a trustee role can create stewards. diff --git a/docs/how-tos/write-did-and-query-verkey/cs/README.md b/docs/how-tos/write-did-and-query-verkey/cs/README.md deleted file mode 100644 index 4c077297dc..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/cs/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Write a DID and Query Its Verkey - -Indy-SDK Developer Walkthrough #1, C# Edition - -[ [Python](../python/README.md) | [Java](../java/README.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Additionally (and depending on your environment), you will need .NET installed. These demos were tested with .NET Core 2.1.302. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a java editor of your -choice and paste the code from [template.partial](template.partial) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `WriteDIDAndQueryVerkey.cs` - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -Now we need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network, and how to trust that the nodes it contacts possess -appropriate keys. - -We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key -material generated during the tutorial. - -![more info on wallets](../wallet-slide.png) - -Copy the contents of [step2.partial](step2.partial) into -`WriteDIDAndQueryVerkey.cs` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.cs`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to put some DIDs and keys in our identity -wallet. Copy the contents of [step3.partial](step3.partial) into -`WriteDIDAndQueryVerkey.cs` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.cs`. - -Study the changes. - -A few operations in indy [can only be done by identities (DIDs) with -special roles](https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md). For example, an DID that is a *steward* can add a node (the one -they own) to the validator pool, and can create DIDs with a *trust anchor* -role. A trust anchor DID can add arbitrary DIDs to the ledger. - -Here, we are populating our identity wallet with DID+keypair material for -one steward identity and one trust anchor identity. The steward identity is -a bootstrapping step, whereas the trust anchor DID is the one we will query -later. - -Notice that the steward DID is created with a seed, but the trust anchor DID is not. -This is because the steward DID and its verkey are already in the ledger; -they were part of the genesis transactions we told the SDK to start with -in the previous step. But we have to also put the DID, verkey, and *private* -signing key (which the ledger doesn't know) into our wallet, so we can use -the signing key to submit an acceptably signed transaction to the ledger. -We will use this steward's signing key to create our *next* DID--the -one for our trust anchor, which is truly new. This is why we use a hard-coded seed -when creating the steward DID--it guarantees that the same DID and key -material are created that the genesis transactions expect. In a production indy pool -such as the Sovrin "live" network, the bootstrapping steward identities -would not have known the seeds. - -### Step 4 - -Now that preparations are complete, we can finally write the DID and verkey -for our trust anchor identity to the ledger. - -Copy the contents of [step4.partial](step4.partial) into -`WriteDIDAndQueryVerkey.cs` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.cs`. - -### Step 5 - -Once we have an identity on the ledger, we can query it. - -Copy the contents of [step5.partial](step5.partial) into -`WriteDIDAndQueryVerkey.cs` on top of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.cs`. - -Only a handful of lines of code matter to our goal here; the rest of -this block is comments and boilerplate cleanup **(which you should not omit!)**. -You should see similarities between the way this query "transaction" and -the preceding write transaction are bundled and sent. - -### Step 6 - -Run the completed demo and observe the whole sequence. - -## More experiments - -Most of the code in this how-to exists to satisfy some preconditions. -Now that you have a trust anchor identity, you can write or query -any number of additional identities to the ledger, with just a handful of -lines of code. Try creating some. - -You might try the ["Rotate a Key"](../../rotate-key/../not-yet-written.md) -how-to, which can be done in only once step one you complete this one. - -You could also try to create a new steward identity without a seed, or -with a different seed, and see what kind of error you get. Only identities -with a trustee role can create stewards. diff --git a/docs/how-tos/write-did-and-query-verkey/cs/Template.cs b/docs/how-tos/write-did-and-query-verkey/cs/Template.cs new file mode 100644 index 0000000000..a8a86609c1 --- /dev/null +++ b/docs/how-tos/write-did-and-query-verkey/cs/Template.cs @@ -0,0 +1,46 @@ +// these are packages from .NET Core and other Nuget packages +using System; +using Newtonsoft.Json.Linq; + +/* +Example demonstrating how to add DID with the role of Trust Anchor as Steward. + +Uses seed to obtain Steward's DID which already exists on the ledger. +Then it generates new DID/Verkey pair for Trust Anchor. +Using Steward's DID, NYM transaction request is built to add Trust Anchor's DID and Verkey +on the ledger with the role of Trust Anchor. +Once the NYM is successfully written on the ledger, it generates new DID/Verkey pair that represents +a client, which are used to create GET_NYM request to query the ledger and confirm Trust Anchor's Verkey. + +For the sake of simplicity, a single wallet is used. In the real world scenario, three different wallets +would be used and DIDs would be exchanged using some channel of communication +*/ + +// These packages are from the Hyperledger Nuget package +using Hyperledger.Indy.DidApi; +using Hyperledger.Indy.LedgerApi; +using Hyperledger.Indy.PoolApi; +using Hyperledger.Indy.WalletApi; + +public class WriteDIDAndQueryVerkey +{ + public static void Demo() + { + + Console.WriteLine("Step 1 -- set up some constants"); + + string walletName = "myWallet"; + string poolName = "pool"; + string stewardSeed = "000000000000000000000000Steward1"; + string poolConfig = "{\"genesis_txn\": \"/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis\"}"; + + // Step 2 code goes here. + + // Step 3 code goes here. + + // Step 4 code goes here. + + // Step 5 code goes here. + + } +} diff --git a/docs/how-tos/write-did-and-query-verkey/cs/template.cs b/docs/how-tos/write-did-and-query-verkey/cs/WriteDIDAndQueryVerkey.cs similarity index 100% rename from docs/how-tos/write-did-and-query-verkey/cs/template.cs rename to docs/how-tos/write-did-and-query-verkey/cs/WriteDIDAndQueryVerkey.cs diff --git a/docs/how-tos/write-did-and-query-verkey/cs/step2.partial b/docs/how-tos/write-did-and-query-verkey/cs/step2.partial deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/how-tos/write-did-and-query-verkey/cs/step3.partial b/docs/how-tos/write-did-and-query-verkey/cs/step3.partial deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/how-tos/write-did-and-query-verkey/cs/step4.partial b/docs/how-tos/write-did-and-query-verkey/cs/step4.partial deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/how-tos/write-did-and-query-verkey/cs/step5.partial b/docs/how-tos/write-did-and-query-verkey/cs/step5.partial deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/how-tos/write-did-and-query-verkey/java/README.md b/docs/how-tos/write-did-and-query-verkey/java/README.md deleted file mode 100644 index bff322b89b..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/java/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Write a DID and Query Its Verkey - -Indy-SDK Developer Walkthrough #1, Java Edition - -[ [Python](../python/README.md) | [.NET](../cs/README.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a java editor of your -choice and paste the code from [template.java](template.java) -into a new doc. We will be modifying this code in later steps. - -Save the doc as `WriteDIDAndQueryVerkey.java` - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -Now we need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network, and how to trust that the nodes it contacts possess -appropriate keys. - -We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key -material generated during the tutorial. - -![more info on wallets](../wallet-slide.png) - -Copy the contents of [step2.java](step2.java) into -`WriteDIDAndQueryVerkey.java` on top of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.java`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to put some DIDs and keys in our identity -wallet. Copy the contents of [step3.java](step3.java) into -`WriteDIDAndQueryVerkey.java` on top of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.java`. - -Study the changes. - -A few operations in indy [can only be done by identities (DIDs) with -special roles](https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md). -For example, a DID that is a *steward* can add a node (the one -they own) to the validator pool, and can create DIDs with a *trust anchor* -role. A trust anchor DID can add arbitrary DIDs to the ledger. - -Here, we are populating our identity wallet with DID+keypair material for -one steward identity and one trust anchor identity. The steward identity is -a bootstrapping step, whereas the trust anchor DID is the one we will query -later. - -Notice that the steward DID is created with a seed, but the trust anchor DID is not. -This is because the steward DID and its verkey are already in the ledger; -they were part of the genesis transactions we told the SDK to start with -in the previous step. But we have to also put the DID, verkey, and *private* -signing key (which the ledger doesn't know) into our wallet, so we can use -the signing key to submit an acceptably signed transaction to the ledger. -We will use this steward's signing key to create our *next* DID--the -one for our trust anchor, which is truly new. This is why we use a hard-coded seed -when creating the steward DID--it guarantees that the same DID and key -material are created that the genesis transactions expect. In a production indy pool -such as the Sovrin "live" network, the bootstrapping steward identities -would not have known the seeds. - -### Step 4 - -Now that preparations are complete, we can finally write the DID and verkey -for our trust anchor identity to the ledger. - -Copy the contents of [step4.java](step4.java) into -`WriteDIDAndQueryVerkey.java` on top of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.java`. - -### Step 5 - -Once we have an identity on the ledger, we can query it. - -Copy the contents of [step5.java](step5.java) into -`WriteDIDAndQueryVerkey.java` on top of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `WriteDIDAndQueryVerkey.java`. - -Only a handful of lines of code matter to our goal here; the rest of -this block is comments and boilerplate cleanup **(which you should not omit!)**. -You should see similarities between the way this query "transaction" and -the preceding write transaction are bundled and sent. - -### Step 6 - -Run the completed demo and observe the whole sequence. - -## More experiments - -Most of the code in this how-to exists to satisfy some preconditions. -Now that you have a trust anchor identity, you can write or query -any number of additional identities to the ledger, with just a handful of -lines of code. Try creating some. - -You might try the ["Rotate a Key"](../../rotate-key/java/README.md) -how-to, which can be done in only once step one you complete this one. - -You could also try to create a new steward identity without a seed, or -with a different seed, and see what kind of error you get. Only identities -with a trustee role can create stewards. diff --git a/docs/how-tos/write-did-and-query-verkey/nodejs/README.md b/docs/how-tos/write-did-and-query-verkey/nodejs/README.md deleted file mode 100644 index fba14e9120..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/nodejs/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# Write a DID and Query Its Verkey - -Indy-SDK Developer Walkthrough #1, NodeJS Edition - -[ [Python](../python/README.md) | [Java](../java/README.md) | [.NET](../cs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Install all dependencies running `npm install`. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a Javascript editor of your -choice and paste the code from [template.js](template.js) -into a new file. We will be modifying this code in later steps. - -Save the doc as `writeDIDAndQueryVerkey.js` - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -Now we need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network, and how to trust that the nodes it contacts possess -appropriate keys. - -We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key -material generated during the tutorial. - -![more info on wallets](../wallet-slide.png) - -Copy the contents of [step 2.js](step2.js) into -`writeDIDAndQueryVerkey.js` instead of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `writeDIDAndQueryVerkey.js`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to put some DIDs and keys in our identity -wallet. Copy the contents of [step3.js](step3.js) into -`writeDIDAndQueryVerkey.js` instead of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `writeDIDAndQueryVerkey.js`. - -Study the changes. - -A few operations in indy [can only be done by identities (DIDs) with -special roles](https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md). -For example, a DID that is a *steward* can add a node (the one -they own) to the validator pool, and can create DIDs with a *trust anchor* -role. A trust anchor DID can add arbitrary DIDs to the ledger. - -Here, we are populating our identity wallet with DID+keypair material for -one steward identity and one trust anchor identity. The steward identity is -a bootstrapping step, whereas the trust anchor DID is the one we will query -later. - -Notice that the steward DID is created with a seed, but the trust anchor DID is not. -This is because the steward DID and its verkey are already in the ledger; -they were part of the genesis transactions we told the SDK to start with -in the previous step. But we have to also put the DID, verkey, and *private* -signing key (which the ledger doesn't know) into our wallet, so we can use -the signing key to submit an acceptably signed transaction to the ledger. -We will use this steward's signing key to create our *next* DID--the -one for our trust anchor, which is truly new. This is why we use a hard-coded seed -when creating the steward DID--it guarantees that the same DID and key -material are created that the genesis transactions expect. In a production indy pool -such as the Sovrin "live" network, the bootstrapping steward identities -would not have known the seeds. - -### Step 4 - -Now that preparations are complete, we can finally write the DID and verkey -for our trust anchor identity to the ledger. - -Copy the contents of [step4.js](step4.js) into -`writeDIDAndQueryVerkey.js` instead of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `writeDIDAndQueryVerkey.js`. - -### Step 5 - -Once we have an identity on the ledger, we can query it. - -Copy the contents of [step5.js](step5.js) into -`writeDIDAndQueryVerkey.js` instead of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `writeDIDAndQueryVerkey.js`. - -Only a handful of lines of code matter to our goal here; the rest of -this block is comments and boilerplate cleanup **(which you should not omit!)**. -You should see similarities between the way this query "transaction" and -the preceding write transaction are bundled and sent. - -### Step 6 - -Run the completed demo and observe the whole sequence. - -## More experiments - -Most of the code in this how-to exists to satisfy some preconditions. -Now that you have a trust anchor identity, you can write or query -any number of additional identities to the ledger, with just a handful of -lines of code. Try creating some. - -You might try the ["Rotate a Key"](../../rotate-key/nodejs/README.md) -how-to, which can be done in only one step one you complete this one. - -You could also try to create a new steward identity without a seed, or -with a different seed, and see what kind of error you get. Only identities -with a trustee role can create stewards. - -There is an additional example in `extra/add_nym.js` which builds and submits -nym request to the ledger. diff --git a/docs/how-tos/write-did-and-query-verkey/python/README.md b/docs/how-tos/write-did-and-query-verkey/python/README.md deleted file mode 100644 index fc345d8429..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/python/README.md +++ /dev/null @@ -1,155 +0,0 @@ -# Write a DID and Query Its Verkey - -Indy-SDK Developer Walkthrough #1, Python Edition - -[ [Java](../java/README.md) | [.NET](../cs/README.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Rust](../rust/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -Ensure you have the 64-bit version of Python 3 installed, as the 32-bit version may have problems loading the Indy .dll files. - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a python editor of your -choice and paste the code from [template.py](template.py) -into a new file. We will be modifying this code in later steps. - -Save the doc as `write_did.py` - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -Install the required python packages by executing: `$ pip install python3-indy asyncio` - -### Step 2 - -Now we need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network, and how to trust that the nodes it contacts possess -appropriate keys. - -We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key -material generated during the tutorial. - -![more info on wallets](../wallet-slide.png) - -Copy the contents of [step2.py](step2.py) into -`write_did.py` instead of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `write_did.py`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to put some DIDs and keys in our identity -wallet. Copy the contents of [step3.py](step3.py) into -`write_did.py` instead of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `write_did.py`. - -Study the changes. - -A few operations in indy [can only be done by identities (DIDs) with -special roles](https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md). For example, a DID that is a *steward* can add a node (the one -they own) to the validator pool, and can create DIDs with a *trust anchor* -role. A trust anchor DID can add arbitrary DIDs to the ledger. - -Here, we are populating our identity wallet with DID+keypair material for -one steward identity and one trust anchor identity. The steward identity is -a bootstrapping step, whereas the trust anchor DID is the one we will query -later. - -Notice that the steward DID is created with a seed, but the trust anchor DID is not. -This is because the steward DID and its verkey is already in the ledger; -they were part of the genesis transactions we told the SDK to start with -in the previous step. But we have to also put the DID, verkey, and *private* -signing key (which the ledger doesn't know) into our wallet, so we can use -the signing key to submit an acceptably signed transaction to the ledger. -We will use this steward's signing key to create our *next* DID--the -one for our trust anchor, which is truly new. This is why we use a hard-coded seed -when creating the steward DID--it guarantees that the same DID and key -material are created that the genesis transactions expect. In a production indy pool -such as the Sovrin "live" network, the bootstrapping steward identities -would not have known the seeds. - -### Step 4 - -Now that preparations are complete, we can finally write the DID and verkey -for our trust anchor identity to the ledger. - -Copy the contents of [step4.py](step4.py) into -`write_did.py` instead of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `write_did.py`. - -### Step 5 - -Once we have an identity on the ledger, we can query it. - -Copy the contents of [step5.py](step5.py) into -`write_did.py` instead of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `write_did.py`. - -Only a handful of lines of code matter to our goal here; the rest of -this block is comments and boilerplate cleanup **(which you should not omit!)**. -You should see similarities between the way this query "transaction" and -the preceding write transaction are bundled, sent, and awaited. - -### Step 6 - -Run the completed demo and observe the whole sequence. - -## More experiments - -Most of the code in this how-to exists to satisfy some preconditions. -Now that you have a trust anchor identity, you can write or query -any number of additional identities to the ledger, with just a handful of -lines of code. Try creating some. - -You might try the ["Rotate a Key"](../../rotate-key/python/README.md) -how-to, which can be done in only one step one you complete this one. - -You could also try to create a new steward identity without a seed, or -with a different seed, and see what kind of error you get. Only identities -with a trustee role can create stewards. - -There is an additional example in `extra/add_nym.py` which builds and submits -nym request to the ledger. - -## Common errors -Error `PoolLedgerConfigAlreadyExistsError`. -Delete config before creating: -```python -try: - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) -except IndyError: - await pool.delete_pool_ledger_config(config_name=pool_name) - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) -``` - -Error `WalletAlreadyExistsError`. -Delete wallet before creating: -```python -try: - await wallet.create_wallet(wallet_config, wallet_credentials) -except IndyError: - await wallet.delete_wallet(wallet_name, wallet_credentials) - await wallet.create_wallet(wallet_config, wallet_credentials) -``` - -Error `CommonIOError`. Make sure that you have set `genesis_file_path` to point -to your `indy-sdk/cli/docker_pool_transactions_genesis`. - -Error `PoolLedgerTimeout`. Make sure that the pool of local nodes in Docker is running on the same ip/ports as -in the `docker_pool_transactions_genesis` (for further details see [How to start local nodes pool with docker](https://github.com/hyperledger/indy-sdk/blob/master/README.md#how-to-start-local-nodes-pool-with-docker)) - - diff --git a/docs/how-tos/write-did-and-query-verkey/python/extra/add_nym.py b/docs/how-tos/write-did-and-query-verkey/python/extra/add_nym.py deleted file mode 100644 index 368444a4c0..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/python/extra/add_nym.py +++ /dev/null @@ -1,147 +0,0 @@ -''' -Created on January 30, 2018 -@author: khoi.ngo - -For updating role of an user in the ledger, a person or an organization in that -ledger must have one of these roles: Trustee, Steward or Trust Anchor. -(https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md) - -This script will setup an environment with a pool (from genesis_txn file), -a wallet inside that pool and get the default Steward DID -(what was added to the ledger during setup). Using that default Steward -to create a Trust Anchor. -Refer to below for detail steps. - -* Setup an environment: - Step 1. Create the pool ledger from genesis txn file - A genesis txn file contains the information about the NODE and - CLIENT machines. With this information after dumped to JSON format - and a name, a pool ledger is created. - Step 2. Open pool ledger to get the pool handle via pool name. - The returned pool handle is used in methods that require pool - connection - Step 3. Create the new Wallet. - Step 4. Get wallet handle to use in methods that require wallet access. - -* Create then store DID and Verkey of the seed_default_steward. - This DID and Verkey was already added to the ledger and - it is a default test Steward that happens during setup. - We will use this Steward to send the schema request - without creating a new one. - Step 5. Create then store DID and Verkey of seed_default_steward - and seed_trust_anchor. - The pair of keys of seed_default_steward will be used to make - a request on step 6. - -* Build and submit nym request to the ledger. - Step 6. Build a nym request. Using default Steward create Trust Anchor - Step 7. Submit the nym request and get the response. - The new Trust Anchor is created. -''' - -import asyncio -import json - -from indy import wallet, did, pool, ledger -from indy.error import IndyError - - -class Variables: - # Initialize pool_handle, wallet_handle variable. - # Set pool_name, wallet_name, seed and the pool configuration path. - # Set a new seed_trustee with exactly 32 characters. - pool_handle = 0 - wallet_handle = 0 - pool_name = "Evenym_pool" - wallet_name = "Evernym_wallet" - pool_txn = "/var/lib/indy/sandbox/pool_transactions_sandbox_genesis" - seed_trustanchor = "TestTrustAnchor00000000000000000" - wallet_credentials = json.dumps({"key": "wallet_key"}) - - -def print_log(value_color): - """set the colors for text.""" - OKGREEN = '\033[92m' - ENDC = '\033[0m' - print(OKGREEN + "\n" + value_color + ENDC) - - -async def build_nym_request(): - try: - - # 1. Create the pool ledger from genesis txn file - # A genesis txn file contains the information about the NODE and - # CLIENT machines. With this information after dumped to JSON format - # and a name, a pool ledger is created. - print_log("1. Creates a new local pool ledger configuration that " - "can be used later to connect pool nodes.") - pool_config = json.dumps({"genesis_txn": str(Variables.pool_txn)}) - await pool.create_pool_ledger_config(Variables.pool_name, pool_config) - print_log("DONE") - - # 2. Open pool ledger to get the pool handle via pool name. - # The returned pool handle is used in methods that require pool - # connection - print_log("2. Open pool ledger and get the pool handle.") - Variables.pool_handle = await pool.open_pool_ledger( - Variables.pool_name, None) - print_log("DONE - Pool handle: " + str(Variables.pool_handle)) - - # 3. Create a new Wallet in the pool. - print_log("3. Creates a new secure wallet with the given unique name.") - await wallet.create_wallet(Variables.pool_name, - Variables.wallet_name, - None, None, Variables.wallet_credentials) - print_log("DONE") - - # 4. Get wallet handle to use in methods that require wallet access. - print_log("4. Get wallet handle to use in methods that require " - "wallet access.") - Variables.wallet_handle = await wallet.open_wallet( - Variables.wallet_name, - None, Variables.wallet_credentials) - print_log("DONE - Wallet_handle: " + str(Variables.wallet_handle)) - - # 5. Create then store DID and verkey of seed_default_steward, - # seed_trustanchor. Steward DID with a verkey were already added - # in the ledger with STEWARD role. - print_log("5. Create then store steward DID and verkey " - "(for verification of signature)") - seed_default_steward = "000000000000000000000000Steward1" - - (default_steward_did, _) = await did.create_and_store_my_did( - Variables.wallet_handle, json.dumps( - {"seed": seed_default_steward})) - (trust_anchor_did, trust_anchor_verkey) = \ - await did.create_and_store_my_did( - Variables.wallet_handle, json.dumps({})) - print_log("DONE - Trust_Anchor[%s][%s]" % (trust_anchor_did, - trust_anchor_verkey)) - - # 6. Prepare data and build the nym request. - print_log("6. Build a nym request. Using default Steward " - "create Trust Anchor") - nym_txn_req = await ledger.build_nym_request( - default_steward_did, - trust_anchor_did, - trust_anchor_verkey, None, - "TRUST_ANCHOR") - print_log("DONE - nym_txn_req: " + str(nym_txn_req)) - - # 7. Send the nym request and get the response. - print_log("7. Send the nym request to the pool ledger") - result = await ledger.sign_and_submit_request( - Variables.pool_handle, - Variables.wallet_handle, - default_steward_did, nym_txn_req) - print_log("DONE - Result: " + str(result)) - except IndyError as E: - print(str(E)) - - -# Create the loop instance using asyncio -loop = asyncio.get_event_loop() -loop.run_until_complete(build_nym_request()) - -# Close the loop instance -loop.close() diff --git a/docs/how-tos/write-did-and-query-verkey/python/step2.py b/docs/how-tos/write-did-and-query-verkey/python/step2.py index 0e0f96a7f3..658a8bba3c 100644 --- a/docs/how-tos/write-did-and-query-verkey/python/step2.py +++ b/docs/how-tos/write-did-and-query-verkey/python/step2.py @@ -1,7 +1,7 @@ # Tell SDK which pool you are going to use. You should have already started # this pool using docker compose or similar. Here, we are dumping the config # just for demonstration purposes. - pool_config = json.dumps({'genesis_txn': genesis_file_path}) + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) print_log('\n1. Create new pool ledger configuration to connect to ledger.\n') await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) diff --git a/docs/how-tos/write-did-and-query-verkey/python/template.py b/docs/how-tos/write-did-and-query-verkey/python/template.py index f790ee4e83..382c53e515 100644 --- a/docs/how-tos/write-did-and-query-verkey/python/template.py +++ b/docs/how-tos/write-did-and-query-verkey/python/template.py @@ -15,16 +15,15 @@ import pprint from indy import pool, ledger, wallet, did -from indy.error import IndyError +from indy.error import IndyError, ErrorCode +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' +genesis_file_path = get_pool_genesis_txn_path(pool_name) + wallet_config = json.dumps({"id": "wallet"}) wallet_credentials = json.dumps({"key": "wallet_key"}) -# Set protocol version to 2 to work with the current version of Indy Node -PROTOCOL_VERSION = 2 - def print_log(value_color="", value_noncolor=""): """set the colors for text.""" diff --git a/docs/how-tos/write-did-and-query-verkey/python/utils.py b/docs/how-tos/write-did-and-query-verkey/python/utils.py new file mode 100644 index 0000000000..a9bdd66d86 --- /dev/null +++ b/docs/how-tos/write-did-and-query-verkey/python/utils.py @@ -0,0 +1,31 @@ +from os import environ +from pathlib import Path +from tempfile import gettempdir + +PROTOCOL_VERSION = 2 + +def get_pool_genesis_txn_path(pool_name): + path_temp = Path(gettempdir()).joinpath("indy") + path = path_temp.joinpath("{}.txn".format(pool_name)) + save_pool_genesis_txn_file(path) + return path + +def pool_genesis_txn_data(): + pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") + + return "\n".join([ + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( + pool_ip, pool_ip), + '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( + pool_ip, pool_ip) + ]) + +def save_pool_genesis_txn_file(path): + data = pool_genesis_txn_data() + path.parent.mkdir(parents=True, exist_ok=True) + with open(str(path), "w+") as f: + f.writelines(data) diff --git a/docs/how-tos/write-did-and-query-verkey/python/write_did_and_query_verkey.py b/docs/how-tos/write-did-and-query-verkey/python/write_did_and_query_verkey.py index 8bc99ff332..839c45e23b 100644 --- a/docs/how-tos/write-did-and-query-verkey/python/write_did_and_query_verkey.py +++ b/docs/how-tos/write-did-and-query-verkey/python/write_did_and_query_verkey.py @@ -17,15 +17,15 @@ import pprint from indy import pool, ledger, wallet, did -from indy.error import IndyError +from indy.error import IndyError, ErrorCode +from utils import get_pool_genesis_txn_path, PROTOCOL_VERSION pool_name = 'pool' -wallet_name = 'wallet' -genesis_file_path = '/home/vagrant/code/evernym/indy-sdk/cli/docker_pool_transactions_genesis' -wallet_credentials = json.dumps({"key": "wallet_key"}) - +genesis_file_path = get_pool_genesis_txn_path(pool_name) +wallet_config = json.dumps({"id": "wallet"}) +wallet_credentials = json.dumps({"key": "wallet_key"}) def print_log(value_color="", value_noncolor=""): """set the colors for text.""" @@ -36,11 +36,17 @@ def print_log(value_color="", value_noncolor=""): async def write_nym_and_query_verkey(): try: + await pool.set_protocol_version(PROTOCOL_VERSION) + # 1. print_log('\n1. Creates a new local pool ledger configuration that is used ' 'later when connecting to ledger.\n') - pool_config = json.dumps({'genesis_txn': genesis_file_path}) - await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + pool_config = json.dumps({'genesis_txn': str(genesis_file_path)}) + try: + await pool.create_pool_ledger_config(config_name=pool_name, config=pool_config) + except IndyError as ex: + if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: + pass # 2. print_log('\n2. Open pool ledger and get handle from libindy\n') @@ -48,11 +54,15 @@ async def write_nym_and_query_verkey(): # 3. print_log('\n3. Creating new secure wallet\n') - await wallet.create_wallet(pool_name, wallet_name, None, None, wallet_credentials) + try: + await wallet.create_wallet(wallet_config, wallet_credentials) + except IndyError as ex: + if ex.error_code == ErrorCode.WalletAlreadyExistsError: + pass # 4. print_log('\n4. Open wallet and get handle from libindy\n') - wallet_handle = await wallet.open_wallet(wallet_name, None, wallet_credentials) + wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) # 5. print_log('\n5. Generating and storing steward DID and verkey\n') @@ -124,7 +134,7 @@ async def write_nym_and_query_verkey(): # 14. print_log('\n14. Deleting created wallet\n') - await wallet.delete_wallet(wallet_name, wallet_credentials) + await wallet.delete_wallet(wallet_config, wallet_credentials) # 15. print_log('\n15. Deleting pool ledger config\n') diff --git a/docs/how-tos/write-did-and-query-verkey/rust/README.md b/docs/how-tos/write-did-and-query-verkey/rust/README.md deleted file mode 100644 index 1144dcc10d..0000000000 --- a/docs/how-tos/write-did-and-query-verkey/rust/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# Write a DID and Query Its Verkey - -Indy-SDK Developer Walkthrough #1, Rust Edition - -[ [Java](../java/README.md) | [.NET](../cs/README.md) | [Node.js](../nodejs/README.md) | [Objective C](../../not-yet-written.md) | [Python](../python/README.md)] - - -## Prerequisites - -Setup your workstation with an indy development virtual machine (VM). See [prerequisites](../../prerequisites.md). - -## Steps - -### Step 1 - -In your normal workstation operating system (not the VM), open a rust editor of your -choice, create empty project and paste the code from [template.rs](template.rs) -into a new file. We will be modifying this code in later steps. - -Save the doc as `write-did-and-query-verkey.rs` - -This is a very simple app framework into which you'll plug the code -you'll be writing. - -### Step 2 - -Now we need to give the SDK some context that it will need -to deal with an indy ledger. This requires us to point the SDK at some -*genesis transactions* that tell the SDK how to contact the ledger on -the network, and how to trust that the nodes it contacts possess -appropriate keys. - -We also need to create an *[identity wallet](https://docs.google.com/presentation/d/1X6F9QVG8M4PqQQLLL_5I6aQ5z7CCpYyYHBNKYMlsqXc/edit#slide=id.g32295399e3_0_73)*, so the SDK can store the DID and key -material generated during the tutorial. - -![more info on wallets](../wallet-slide.png) - -Copy the contents of [step2.rs](step2.rs) into -`write-did-and-query-verkey.rs` instead of the `Step 2 code goes here` placeholder comment. - -Save the updated version of `write-did-and-query-verkey.rs`. - -Study the changes. Scaffolding code like this is likely to appear in anything -that uses indy. - -### Step 3 - -Now we need to put some DIDs and keys in our identity -wallet. Copy the contents of [step3.rs](step3.rs) into -`write-did-and-query-verkey.rs` instead of the `Step 3 code goes here` placeholder comment. - -Save the updated version of `write-did-and-query-verkey.rs`. - -Study the changes. - -A few operations in indy [can only be done by identities (DIDs) with -special roles](https://github.com/hyperledger/indy-node/blob/master/docs/auth_rules.md). For example, a DID that is a *steward* can add a node (the one -they own) to the validator pool, and can create DIDs with a *trust anchor* -role. A trust anchor DID can add arbitrary DIDs to the ledger. - -Here, we are populating our identity wallet with DID+keypair material for -one steward identity and one trust anchor identity. The steward identity is -a bootstrapping step, whereas the trust anchor DID is the one we will query -later. - -Notice that the steward DID is created with a seed, but the trust anchor DID is not. -This is because the steward DID and its verkey is already in the ledger; -they were part of the genesis transactions we told the SDK to start with -in the previous step. But we have to also put the DID, verkey, and *private* -signing key (which the ledger doesn't know) into our wallet, so we can use -the signing key to submit an acceptably signed transaction to the ledger. -We will use this steward's signing key to create our *next* DID--the -one for our trust anchor, which is truly new. This is why we use a hard-coded seed -when creating the steward DID--it guarantees that the same DID and key -material are created that the genesis transactions expect. In a production indy pool -such as the Sovrin "live" network, the bootstrapping steward identities -would not have known the seeds. - -### Step 4 - -Now that preparations are complete, we can finally write the DID and verkey -for our trust anchor identity to the ledger. - -Copy the contents of [step4.rs](step4.rs) into -`write-did-and-query-verkey.rs` instead of the `Step 4 code goes here` placeholder comment. - -Save the updated version of `write-did-and-query-verkey.rs`. - -### Step 5 - -Once we have an identity on the ledger, we can query it. - -Copy the contents of [step5.rs](step5.rs) into -`write-did-and-query-verkey.rs` instead of the `Step 5 code goes here` placeholder comment. - -Save the updated version of `write-did-and-query-verkey.rs`. - -Only a handful of lines of code matter to our goal here; the rest of -this block is comments and boilerplate cleanup **(which you should not omit!)**. -You should see similarities between the way this query "transaction" and -the preceding write transaction are bundled, sent, and awaited. - -### Step 6 - -Run the completed demo and observe the whole sequence. - -## More experiments - -Most of the code in this how-to exists to satisfy some preconditions. -Now that you have a trust anchor identity, you can write or query -any number of additional identities to the ledger, with just a handful of -lines of code. Try creating some. - -You might try the ["Rotate a Key"](../../rotate-key/rust/README.md) -how-to, which can be done in only one step one you complete this one. - -You could also try to create a new steward identity without a seed, or -with a different seed, and see what kind of error you get. Only identities -with a trustee role can create stewards. diff --git a/docs/migration-guides/migration-guide-1.7.0-1.8.0.md b/docs/migration-guides/migration-guide-1.7.0-1.8.0.md index 8448991f21..726ba702f9 100644 --- a/docs/migration-guides/migration-guide-1.7.0-1.8.0.md +++ b/docs/migration-guides/migration-guide-1.7.0-1.8.0.md @@ -278,4 +278,11 @@ indy_build_get_auth_rule_request(command_handle: CommandHandle, - \ No newline at end of file + + +## Libindy 1.8.2 to 1.8.3 migration Guide + +Updated behavior of `indy_build_auth_rule_request` and `indy_build_get_auth_rule_request` API functions: +* `new_value` can be empty string for `ADD` action. +* `new_value` can be null for `EDIT` action. +* `old_value` is skipped during transaction serialization for `ADD` action. \ No newline at end of file diff --git a/libindy/Cargo.lock b/libindy/Cargo.lock index ae78cb8b56..34f9026970 100644 --- a/libindy/Cargo.lock +++ b/libindy/Cargo.lock @@ -416,11 +416,11 @@ dependencies = [ [[package]] name = "indy" -version = "1.8.2" +version = "1.8.3" dependencies = [ "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-sys 1.8.2", + "indy-sys 1.8.3", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -455,7 +455,7 @@ dependencies = [ [[package]] name = "indy-sys" -version = "1.8.2" +version = "1.8.3" dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -503,7 +503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libindy" -version = "1.8.2" +version = "1.8.3" dependencies = [ "android_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -519,9 +519,9 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indy 1.8.2", + "indy 1.8.3", "indy-crypto 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "indy-sys 1.8.2", + "indy-sys 1.8.3", "int_traits 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/libindy/Cargo.toml b/libindy/Cargo.toml index b6d0eabe1b..84a18fc0dc 100644 --- a/libindy/Cargo.toml +++ b/libindy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libindy" -version = "1.8.2" +version = "1.8.3" authors = [ "Sergej Pupykin ", "Vyacheslav Gudkov ", diff --git a/libindy/debian/changelog b/libindy/debian/changelog index 9f98c15645..70ab5d0cc5 100644 --- a/libindy/debian/changelog +++ b/libindy/debian/changelog @@ -1,7 +1,14 @@ -libindy (1.8.2) unstable; urgency=medium +libindy (1.8.3) unstable; urgency=medium [ Hyperledger ] + +## 1.8.3 +* Bugfixes: + * Fixed behavior of `auth_rule` and `get_auth_rule` request builders. + * Fixed `boolean` datatype representation for FFI. + * others minor bugfixes + ## 1.8.2 Added new functions to Libindy Ledger API: * `indy_build_auth_rule_request` to change an existing ledger auth rule. diff --git a/libindy/include/indy_ledger.h b/libindy/include/indy_ledger.h index f62fabccfc..d1a43a2328 100644 --- a/libindy/include/indy_ledger.h +++ b/libindy/include/indy_ledger.h @@ -963,8 +963,8 @@ extern "C" { /// 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. + /// old_value: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). + /// new_value: (Optional) 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. @@ -1013,7 +1013,7 @@ extern "C" { /// txn_type: (Optional) target ledger transaction alias or associated value. /// action: (Optional) target action type. Can be either "ADD" or "EDIT". /// field: (Optional) target transaction field. - /// old_value: (Optional) old value of field, which can be changed to a new_value (must be specified for EDIT action). + /// old_value: (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). /// new_value: (Optional) new value that can be used to fill the field. /// /// cb: Callback that takes command result as parameter. diff --git a/libindy/include/indy_types.h b/libindy/include/indy_types.h index debdfcc6f9..7321954068 100644 --- a/libindy/include/indy_types.h +++ b/libindy/include/indy_types.h @@ -2,12 +2,13 @@ #define __indy__types__included__ #include +#include typedef uint8_t indy_u8_t; typedef uint32_t indy_u32_t; typedef int32_t indy_i32_t; typedef int32_t indy_handle_t; -typedef unsigned int indy_bool_t; +typedef bool indy_bool_t; typedef long long indy_i64_t; typedef unsigned long long indy_u64_t; diff --git a/libindy/src/api/ledger.rs b/libindy/src/api/ledger.rs index abfaab24f6..6da9d2913c 100644 --- a/libindy/src/api/ledger.rs +++ b/libindy/src/api/ledger.rs @@ -1843,8 +1843,8 @@ pub extern fn indy_get_response_metadata(command_handle: CommandHandle, /// 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. +/// old_value: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). +/// new_value: (Optional) 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. @@ -1892,7 +1892,7 @@ pub extern fn indy_build_auth_rule_request(command_handle: CommandHandle, 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_opt_c_str!(new_value, ErrorCode::CommonInvalidParam7); check_useful_c_str!(constraint, ErrorCode::CommonInvalidParam8); check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam9); @@ -1936,7 +1936,7 @@ pub extern fn indy_build_auth_rule_request(command_handle: CommandHandle, /// txn_type: (Optional) target ledger transaction alias or associated value. /// action: (Optional) target action type. Can be either "ADD" or "EDIT". /// field: (Optional) target transaction field. -/// old_value: (Optional) old value of field, which can be changed to a new_value (must be specified for EDIT action). +/// old_value: (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). /// new_value: (Optional) new value that can be used to fill the field. /// /// cb: Callback that takes command result as parameter. diff --git a/libindy/src/commands/crypto.rs b/libindy/src/commands/crypto.rs index bd9bf4c175..4ccf5b6b29 100644 --- a/libindy/src/commands/crypto.rs +++ b/libindy/src/commands/crypto.rs @@ -553,12 +553,12 @@ impl CryptoCommandExecutor { recipient_verkey: recipient.header.kid }; - return serde_json::to_vec(&res).map_err(|err| { + serde_json::to_vec(&res).map_err(|err| { err_msg(IndyErrorKind::InvalidStructure, format!( "Failed to serialize message {}", err )) - }); + }) } fn _find_correct_recipient(&self, protected_struct: Protected, wallet_handle: WalletHandle) -> IndyResult<(Recipient, bool)>{ @@ -574,7 +574,7 @@ impl CryptoCommandExecutor { return Ok((recipient.clone(), recipient.header.sender.is_some())) } } - return Err(IndyError::from(IndyErrorKind::WalletItemNotFound)); + Err(IndyError::from(IndyErrorKind::WalletItemNotFound)) } fn _unpack_cek_authcrypt(&self, recipient: Recipient, wallet_handle: WalletHandle) -> IndyResult<(Option, chacha20poly1305_ietf::Key)> { diff --git a/libindy/src/commands/did.rs b/libindy/src/commands/did.rs index 6a0a0a3329..e36c35e4da 100644 --- a/libindy/src/commands/did.rs +++ b/libindy/src/commands/did.rs @@ -417,7 +417,7 @@ impl DidCommandExecutor { match endpoint { Ok(endpoint) => cb(Ok((endpoint.ha, endpoint.verkey))), - Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => return self._fetch_attrib_from_ledger(wallet_handle, + Err(ref err) if err.kind() == IndyErrorKind::WalletItemNotFound => self._fetch_attrib_from_ledger(wallet_handle, pool_handle, &did, DidCommand::GetEndpointForDid( @@ -425,7 +425,7 @@ impl DidCommandExecutor { pool_handle, did.clone(), cb)), - Err(err) => return cb(Err(err)), + Err(err) => cb(Err(err)), }; } @@ -579,22 +579,22 @@ impl DidCommandExecutor { fn _call_error_cb(&self, command: DidCommand, err: IndyError) { match command { DidCommand::CreateAndStoreMyDid(_, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } DidCommand::ReplaceKeysStart(_, _, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } DidCommand::ReplaceKeysApply(_, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } DidCommand::StoreTheirDid(_, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } DidCommand::KeyForDid(_, _, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } DidCommand::GetEndpointForDid(_, _, _, cb) => { - return cb(Err(err)); + cb(Err(err)); } _ => {} } diff --git a/libindy/src/commands/ledger.rs b/libindy/src/commands/ledger.rs index 0b30ed3e12..b947e4fa9b 100644 --- a/libindy/src/commands/ledger.rs +++ b/libindy/src/commands/ledger.rs @@ -191,7 +191,7 @@ pub enum LedgerCommand { String, // auth action String, // field Option, // old value - String, // new value + Option, // new value String, // constraint Box) + Send>), BuildGetAuthRuleRequest( @@ -381,7 +381,7 @@ impl LedgerCommandExecutor { } 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)); + cb(self.build_auth_rule_request(&submitter_did, &txn_type, &action, &field, old_value.as_ref().map(String::as_str), new_value.as_ref().map(String::as_str), &constraint)); } LedgerCommand::BuildGetAuthRuleRequest(submitter_did, txn_type, action, field, old_value, new_value, cb) => { info!(target: "ledger_command_executor", "BuildGetAuthRuleRequest command received"); @@ -927,7 +927,7 @@ impl LedgerCommandExecutor { action: &str, field: &str, old_value: Option<&str>, - new_value: &str, + new_value: Option<&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); diff --git a/libindy/src/domain/anoncreds/credential_definition.rs b/libindy/src/domain/anoncreds/credential_definition.rs index 59148cc632..0b659313b9 100644 --- a/libindy/src/domain/anoncreds/credential_definition.rs +++ b/libindy/src/domain/anoncreds/credential_definition.rs @@ -11,8 +11,8 @@ use indy_crypto::cl::{ use std::collections::HashMap; use named_type::NamedType; -pub const CL_SIGNATURE_TYPE: &'static str = "CL"; -pub const CRED_DEF_MARKER: &'static str = "3"; +pub const CL_SIGNATURE_TYPE: &str = "CL"; +pub const CRED_DEF_MARKER: &str = "3"; #[derive(Deserialize, Debug, Serialize, PartialEq, Clone)] pub enum SignatureType { diff --git a/libindy/src/domain/anoncreds/revocation_registry_definition.rs b/libindy/src/domain/anoncreds/revocation_registry_definition.rs index 319c7f6e8d..d143374cc4 100644 --- a/libindy/src/domain/anoncreds/revocation_registry_definition.rs +++ b/libindy/src/domain/anoncreds/revocation_registry_definition.rs @@ -5,8 +5,8 @@ use super::DELIMITER; use std::collections::{HashMap, HashSet}; use named_type::NamedType; -pub const CL_ACCUM: &'static str = "CL_ACCUM"; -pub const REV_REG_DEG_MARKER: &'static str = "4"; +pub const CL_ACCUM: &str = "CL_ACCUM"; +pub const REV_REG_DEG_MARKER: &str = "4"; #[derive(Deserialize, Debug, Serialize)] pub struct RevocationRegistryConfig { diff --git a/libindy/src/domain/anoncreds/schema.rs b/libindy/src/domain/anoncreds/schema.rs index 7b453338bc..5268566fa9 100644 --- a/libindy/src/domain/anoncreds/schema.rs +++ b/libindy/src/domain/anoncreds/schema.rs @@ -2,7 +2,7 @@ use super::DELIMITER; use std::collections::{HashMap, HashSet}; -pub const SCHEMA_MARKER: &'static str = "2"; +pub const SCHEMA_MARKER: &str = "2"; pub const MAX_ATTRIBUTES_COUNT: usize = 125; #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/libindy/src/domain/ledger/auth_rule.rs b/libindy/src/domain/ledger/auth_rule.rs index 109bafdc5e..53a9ef3c31 100644 --- a/libindy/src/domain/ledger/auth_rule.rs +++ b/libindy/src/domain/ledger/auth_rule.rs @@ -22,8 +22,8 @@ pub enum Constraint { #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct RoleConstraint { - pub sig_count: u32, - pub role: String, + pub sig_count: Option, + pub role: Option, #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -36,59 +36,124 @@ pub struct CombinationConstraint { } #[derive(Serialize, PartialEq, Debug)] -pub struct AuthRuleOperation { +#[serde(untagged)] +pub enum AuthRuleOperation { + Add(AddAuthRuleOperation), + Edit(EditAuthRuleOperation), +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct AddAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub new_value: Option, + pub constraint: Constraint, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct EditAuthRuleOperation { #[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 new_value: Option, 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, + old_value: Option, new_value: Option, constraint: Constraint) -> AuthRuleOperation { + match auth_action { + AuthAction::ADD => + AuthRuleOperation::Add(AddAuthRuleOperation { + _type: AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + new_value, + constraint, + }), + AuthAction::EDIT => + AuthRuleOperation::Edit(EditAuthRuleOperation { + _type: AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + old_value, + new_value, + constraint, + }) } } } #[derive(Serialize, PartialEq, Debug)] -pub struct GetAuthRuleOperation { +#[serde(untagged)] +pub enum GetAuthRuleOperation { + All(GetAllAuthRuleOperation), + Add(GetAddAuthRuleOperation), + Edit(GetEditAuthRuleOperation), +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAllAuthRuleOperation { #[serde(rename = "type")] pub _type: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub auth_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub field: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub auth_action: Option, - #[serde(skip_serializing_if = "Option::is_none")] +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetAddAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, + pub new_value: Option, +} + +#[derive(Serialize, PartialEq, Debug)] +pub struct GetEditAuthRuleOperation { + #[serde(rename = "type")] + pub _type: String, + pub auth_type: String, + pub field: String, + pub auth_action: AuthAction, pub old_value: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub new_value: Option + pub new_value: Option, } impl GetAuthRuleOperation { - pub fn new(auth_type: Option, field: Option, auth_action: Option, - old_value: Option, new_value: Option) -> GetAuthRuleOperation { - GetAuthRuleOperation { + pub fn get_all() -> GetAuthRuleOperation { + GetAuthRuleOperation::All(GetAllAuthRuleOperation { _type: GET_AUTH_RULE.to_string(), - auth_type, - field, - auth_action, - old_value, - new_value, + }) + } + + pub fn get_one(auth_type: String, field: String, auth_action: AuthAction, + old_value: Option, new_value: Option) -> GetAuthRuleOperation { + match auth_action { + AuthAction::ADD => + GetAuthRuleOperation::Add(GetAddAuthRuleOperation { + _type: GET_AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + new_value, + }), + AuthAction::EDIT => + GetAuthRuleOperation::Edit(GetEditAuthRuleOperation { + _type: GET_AUTH_RULE.to_string(), + auth_type, + field, + auth_action, + old_value, + new_value, + }) } } } \ No newline at end of file diff --git a/libindy/src/domain/ledger/request.rs b/libindy/src/domain/ledger/request.rs index 585d2ee111..ba449299af 100644 --- a/libindy/src/domain/ledger/request.rs +++ b/libindy/src/domain/ledger/request.rs @@ -4,7 +4,7 @@ use time; use std::sync::atomic::{AtomicUsize, Ordering}; -pub const DEFAULT_LIBIDY_DID: &'static str = "LibindyDid111111111111"; +pub const DEFAULT_LIBIDY_DID: &str = "LibindyDid111111111111"; pub struct ProtocolVersion {} diff --git a/libindy/src/services/anoncreds/prover.rs b/libindy/src/services/anoncreds/prover.rs index 6e8a6ad1f8..c9ba56ad71 100644 --- a/libindy/src/services/anoncreds/prover.rs +++ b/libindy/src/services/anoncreds/prover.rs @@ -27,7 +27,7 @@ use domain::anoncreds::schema::SchemaV1; use errors::prelude::*; use services::anoncreds::helpers::*; -const ATTRIBUTE_EXISTENCE_MARKER: &'static str = "1"; +const ATTRIBUTE_EXISTENCE_MARKER: &str = "1"; pub struct Prover {} diff --git a/libindy/src/services/crypto/mod.rs b/libindy/src/services/crypto/mod.rs index b7fc8340e5..cdda9e9fef 100644 --- a/libindy/src/services/crypto/mod.rs +++ b/libindy/src/services/crypto/mod.rs @@ -20,7 +20,7 @@ use self::hex::FromHex; mod ed25519; -pub const DEFAULT_CRYPTO_TYPE: &'static str = "ed25519"; +pub const DEFAULT_CRYPTO_TYPE: &str = "ed25519"; //TODO fix this crypto trait so it matches the functions below //TODO create a second crypto trait for additional functions diff --git a/libindy/src/services/ledger/merkletree/merkletree.rs b/libindy/src/services/ledger/merkletree/merkletree.rs index 18f34d4b73..a46c8ad368 100644 --- a/libindy/src/services/ledger/merkletree/merkletree.rs +++ b/libindy/src/services/ledger/merkletree/merkletree.rs @@ -101,7 +101,7 @@ impl MerkleTree { for i in rh { ret.push_str(&format!("{:02x}", i)); } - return ret; + ret } /// Returns the height of Merkle tree diff --git a/libindy/src/services/ledger/merkletree/mod.rs b/libindy/src/services/ledger/merkletree/mod.rs index 113e837f10..8fe6dc968e 100644 --- a/libindy/src/services/ledger/merkletree/mod.rs +++ b/libindy/src/services/ledger/merkletree/mod.rs @@ -15,32 +15,32 @@ impl MerkleTree { val &= val - 1; ret += 1; } - return ret; + ret } pub fn find_hash<'a>(from: &'a Tree, required_hash: &Vec) -> Option<&'a Tree> { match from { &Tree::Empty { .. } => { assert!(false); - return None; + None } &Tree::Node { ref left, ref right, ref hash, .. } => { if hash == required_hash { - return Some(from); + Some(from) } else { let right = MerkleTree::find_hash(right, required_hash); match right { Some(r) => { - return Some(r); + Some(r) } None => { let left = MerkleTree::find_hash(left, required_hash); match left { Some(r) => { - return Some(r); + Some(r) } None => { - return None; + None } } } @@ -49,9 +49,9 @@ impl MerkleTree { } &Tree::Leaf { ref hash, .. } => { if hash == required_hash { - return Some(from); + Some(from) } else { - return None; + None } } } @@ -123,7 +123,7 @@ impl MerkleTree { return Ok(false); } - return Ok(true); + Ok(true) } pub fn append(&mut self, node: TreeLeafData) -> IndyResult<()> { diff --git a/libindy/src/services/ledger/mod.rs b/libindy/src/services/ledger/mod.rs index 0278e1b533..eb45b5b06c 100644 --- a/libindy/src/services/ledger/mod.rs +++ b/libindy/src/services/ledger/mod.rs @@ -549,32 +549,22 @@ impl LedgerService { Ok(res) } - fn _parse_auth_action(&self, action: &str, old_value: Option<&str>) -> IndyResult { - let action = serde_json::from_str::(&format!("\"{}\"", action)) - .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Cannot parse auth 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")); - } - - Ok(action) - } - 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 { + old_value: Option<&str>, new_value: Option<&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 = self._parse_auth_action(action, old_value)?; + let action = serde_json::from_str::(&format!("\"{}\"", action)) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Cannot parse auth action: {}", err)))?; 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); + old_value.map(String::from), new_value.map(String::from), constraint); let request = Request::build_request(Some(submitter_did), operation) .to_indy(IndyErrorKind::InvalidState, "AUTH_RULE request json is invalid")?; @@ -589,29 +579,24 @@ impl LedgerService { info!("build_get_auth_rule_request >>> submitter_did: {:?}, auth_type: {:?}, auth_action: {:?}, field: {:?}, \ old_value: {:?}, new_value: {:?}", submitter_did, auth_type, auth_action, field, old_value, new_value); - if !(auth_type.is_some() && auth_action.is_some() && field.is_some() && new_value.is_some() || - auth_type.is_none() && auth_action.is_none() && field.is_none() && new_value.is_none()) { - return Err(err_msg(IndyErrorKind::InvalidStructure, "Either none or all transaction related parameters must be specified (`old_value` can be skipped for `ADD` action)")); - } + let operation = match (auth_type, auth_action, field) { + (None, None, None) => GetAuthRuleOperation::get_all(), + (Some(auth_type), Some(auth_action), Some(field)) => { + let type_ = txn_name_to_code(&auth_type) + .ok_or(err_msg(IndyErrorKind::InvalidStructure, format!("Unsupported `auth_type`: {}", auth_type)))?; - let auth_type = match auth_type { - Some(type_) => Some( - txn_name_to_code(&type_) - .ok_or(err_msg(IndyErrorKind::InvalidStructure, format!("Unsupported `auth_type`: {}", type_)))?), - None => None - }; + let action = serde_json::from_str::(&format!("\"{}\"", auth_action)) + .map_err(|err| IndyError::from_msg(IndyErrorKind::InvalidStructure, format!("Cannot parse auth action: {}", err)))?; - let auth_action = match auth_action { - Some(action) => Some(self._parse_auth_action(action, old_value)?), - None => None + GetAuthRuleOperation::get_one(type_.to_string(), + field.to_string(), + action, + old_value.map(String::from), + new_value.map(String::from)) + } + _ => return Err(err_msg(IndyErrorKind::InvalidStructure, "Either none or all transaction related parameters must be specified.")) }; - let operation = GetAuthRuleOperation::new(auth_type.map(String::from), - field.map(String::from), - auth_action, - old_value.map(String::from), - new_value.map(String::from)); - let request = Request::build_request(submitter_did, operation) .to_indy(IndyErrorKind::InvalidState, "GET_AUTH_RULE request json is invalid")?; @@ -1007,9 +992,9 @@ mod tests { fn _role_constraint() -> Constraint { Constraint::RoleConstraint(RoleConstraint { - sig_count: 0, + sig_count: Some(0), metadata: None, - role: String::new(), + role: Some(String::new()), need_to_be_owner: Some(false), }) } @@ -1032,7 +1017,7 @@ mod tests { }); let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, ADD_AUTH_ACTION, FIELD, - None, NEW_VALUE, + None, Some(NEW_VALUE), &_role_constraint_json()).unwrap(); check_request(&request, expected_result); } @@ -1065,7 +1050,7 @@ mod tests { }); let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, ADD_AUTH_ACTION, FIELD, - None, NEW_VALUE, + None, Some(NEW_VALUE), &constraint_json).unwrap(); check_request(&request, expected_result); @@ -1086,41 +1071,49 @@ mod tests { }); let request = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, EDIT_AUTH_ACTION, FIELD, - Some(OLD_VALUE), NEW_VALUE, + Some(OLD_VALUE), Some(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() { + fn build_auth_rule_request_works_for_invalid_auth_type() { let ledger_service = LedgerService::new(); - let res = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, EDIT_AUTH_ACTION, FIELD, - None, NEW_VALUE, + let res = ledger_service.build_auth_rule_request(IDENTIFIER, "WRONG", ADD_AUTH_ACTION, FIELD, + None, Some(NEW_VALUE), &_role_constraint_json()); assert_kind!(IndyErrorKind::InvalidStructure, res); } #[test] - fn build_auth_rule_request_works_for_invalid_auth_type() { + fn build_auth_rule_request_works_for_invalid_auth_action() { 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()); + let res = ledger_service.build_auth_rule_request(IDENTIFIER, NYM, "WRONG", FIELD, None, Some(NEW_VALUE), &_role_constraint_json()); assert_kind!(IndyErrorKind::InvalidStructure, res); } #[test] - fn build_auth_rule_request_works_for_invalid_auth_action() { + fn build_get_auth_rule_request_works_for_add_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); + let expected_result = json!({ + "type": GET_AUTH_RULE, + "auth_type": NYM, + "field": FIELD, + "new_value": NEW_VALUE, + "auth_action": AuthAction::ADD, + }); + + let request = ledger_service.build_get_auth_rule_request(Some(IDENTIFIER), Some(NYM), + Some(ADD_AUTH_ACTION), Some(FIELD), + None, Some(NEW_VALUE)).unwrap(); + check_request(&request, expected_result); } #[test] - fn build_get_auth_rule_request_works_for_all_fields() { + fn build_get_auth_rule_request_works_for_edit_action() { let ledger_service = LedgerService::new(); let expected_result = json!({ @@ -1129,11 +1122,11 @@ mod tests { "field": FIELD, "old_value": OLD_VALUE, "new_value": NEW_VALUE, - "auth_action": AuthAction::ADD, + "auth_action": AuthAction::EDIT, }); let request = ledger_service.build_get_auth_rule_request(Some(IDENTIFIER), Some(NYM), - Some(ADD_AUTH_ACTION), Some(FIELD), + Some(EDIT_AUTH_ACTION), Some(FIELD), Some(OLD_VALUE), Some(NEW_VALUE)).unwrap(); check_request(&request, expected_result); } diff --git a/libindy/src/services/pool/catchup.rs b/libindy/src/services/pool/catchup.rs index e63e358bec..63ee6362af 100644 --- a/libindy/src/services/pool/catchup.rs +++ b/libindy/src/services/pool/catchup.rs @@ -108,9 +108,9 @@ fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option 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)); + Ok(CatchupProgress::Restart(merkle_tree)) } else { - return Err(err); + Err(err) } } @@ -121,10 +121,10 @@ fn _try_to_catch_up(ledger_status: &(String, usize, Option>), merkle if target_mt_size == cur_mt_size { if cur_mt_hash.eq(target_mt_root) { - return Ok(CatchupProgress::NotNeeded(merkle_tree.clone())); + Ok(CatchupProgress::NotNeeded(merkle_tree.clone())) } else { - return Err(err_msg(IndyErrorKind::InvalidState, - "Ledger merkle tree is not acceptable for current tree.")); + Err(err_msg(IndyErrorKind::InvalidState, + "Ledger merkle tree is not acceptable for current tree.")) } } else if target_mt_size > cur_mt_size { let target_mt_root = target_mt_root @@ -137,9 +137,9 @@ fn _try_to_catch_up(ledger_status: &(String, usize, Option>), merkle &Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?, }; - return Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone())); + Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone())) } else { - return Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger")); + Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger")) } } diff --git a/libindy/src/services/pool/events.rs b/libindy/src/services/pool/events.rs index f9d0f0987f..f53cb24dcb 100644 --- a/libindy/src/services/pool/events.rs +++ b/libindy/src/services/pool/events.rs @@ -6,7 +6,7 @@ use errors::prelude::*; use services::ledger::merkletree::merkletree::MerkleTree; use services::pool::{PoolService, types::*}; -pub const REQUESTS_FOR_STATE_PROOFS: [&'static str; 7] = [ +pub const REQUESTS_FOR_STATE_PROOFS: [&str; 8] = [ constants::GET_NYM, constants::GET_SCHEMA, constants::GET_CRED_DEF, @@ -14,9 +14,10 @@ pub const REQUESTS_FOR_STATE_PROOFS: [&'static str; 7] = [ constants::GET_REVOC_REG, constants::GET_REVOC_REG_DEF, constants::GET_REVOC_REG_DELTA, + constants::GET_AUTH_RULE, ]; -const REQUEST_FOR_FULL: [&'static str; 2] = [ +const REQUEST_FOR_FULL: [&str; 2] = [ constants::POOL_RESTART, constants::GET_VALIDATOR_INFO, ]; diff --git a/libindy/src/services/pool/mod.rs b/libindy/src/services/pool/mod.rs index 5d7c356e96..163774866b 100644 --- a/libindy/src/services/pool/mod.rs +++ b/libindy/src/services/pool/mod.rs @@ -165,7 +165,7 @@ impl PoolService { self.pending_pools.try_borrow_mut()? .insert(new_pool.get_id(), ZMQPool::new(new_pool, send_cmd_sock)); - return Ok(pool_handle); + Ok(pool_handle) } pub fn add_open_pool(&self, pool_id: i32) -> IndyResult { diff --git a/libindy/src/services/pool/state_proof/node.rs b/libindy/src/services/pool/state_proof/node.rs index 40b33b5136..c835885348 100644 --- a/libindy/src/services/pool/state_proof/node.rs +++ b/libindy/src/services/pool/state_proof/node.rs @@ -88,18 +88,18 @@ impl rlp::Decodable for Node { RlpPrototype::List(Node::PAIR_SIZE) => { let path: Vec = rlp.at(0)?.as_val()?; if path[0] & Node::IS_LEAF_MASK == Node::IS_LEAF_MASK { - return Ok(Node::Leaf(Leaf { + Ok(Node::Leaf(Leaf { path: rlp.at(0)?.as_val()?, value: rlp.at(1)?.as_val()?, - })); + })) } else if path[0] & Node::IS_LEAF_MASK == 0x00 { - return Ok(Node::Extension(Extension { + Ok(Node::Extension(Extension { path: rlp.at(0)?.as_val()?, next: Box::new(rlp.at(1)?.as_val()?), - })); + })) } else { error!("RLP for path in Patricia Merkle Trie contains incorrect flags byte {}", path[0]); - return Err(RlpDecoderError::Custom("Path contains incorrect flags byte")); + Err(RlpDecoderError::Custom("Path contains incorrect flags byte")) } } RlpPrototype::List(Node::FULL_SIZE) => { @@ -119,17 +119,17 @@ impl rlp::Decodable for Node { if !rlp.at(Node::RADIX)?.is_empty() { value = Some(rlp.at(Node::RADIX)?.as_val()?) } - return Ok(Node::Full(FullNode { + Ok(Node::Full(FullNode { nodes: nodes, value: value, - })); + })) } RlpPrototype::Data(Node::HASH_SIZE) => { - return Ok(Node::Hash(rlp.as_val()?)); + Ok(Node::Hash(rlp.as_val()?)) } _ => { error!("Unexpected data while parsing Patricia Merkle Trie: {:?}: {:?}", rlp.prototype(), rlp); - return Err(RlpDecoderError::Custom("Unexpected data")); + Err(RlpDecoderError::Custom("Unexpected data")) } } } @@ -164,9 +164,9 @@ impl Node { } } - return Err(err_msg(IndyErrorKind::InvalidStructure, "Unexpected data format of value in Patricia Merkle Trie")); + Err(err_msg(IndyErrorKind::InvalidStructure, "Unexpected data format of value in Patricia Merkle Trie")) } - None => return Ok(None) + None => Ok(None) } } fn _get_value<'a, 'b>(&'a self, db: &'a TrieDB, path: &'b [u8]) -> IndyResult>> { @@ -179,7 +179,7 @@ impl Node { if let Some(ref next) = node.nodes[path[0] as usize] { return next._get_value(db, &path[1..]); } - return Ok(None); + Ok(None) } &Node::Hash(ref hash) => { let hash = NodeHash::from_slice(hash.as_slice()); @@ -199,9 +199,9 @@ impl Node { trace!("Node::_get_value in Leaf searched path {:?}, stored path {:?}", String::from_utf8(path.to_vec()), String::from_utf8(pair_path.clone())); if pair_path == path { - return Ok(Some(&pair.value)); + Ok(Some(&pair.value)) } else { - return Ok(None); + Ok(None) } } &Node::Extension(ref pair) => { @@ -212,9 +212,9 @@ impl Node { } if path.starts_with(&pair_path) { - return pair.next._get_value(db, &path[pair_path.len()..]); + pair.next._get_value(db, &path[pair_path.len()..]) } else { - return Ok(None); + Ok(None) } } } @@ -228,7 +228,7 @@ impl Node { nibble_path.push(s & 0x0F); } - return nibble_path; + nibble_path } fn parse_path(path: &[u8]) -> (bool, Vec) { @@ -238,6 +238,6 @@ impl Node { if is_odd { nibbles.insert(0, path[0] & 0x0F); } - return (is_leaf, nibbles); + (is_leaf, nibbles) } } \ No newline at end of file diff --git a/libindy/src/services/wallet/encryption.rs b/libindy/src/services/wallet/encryption.rs index bdbb08a48f..dba85e60ff 100644 --- a/libindy/src/services/wallet/encryption.rs +++ b/libindy/src/services/wallet/encryption.rs @@ -89,7 +89,7 @@ pub(super) fn encrypt_tag_names(tag_names: &[&str], tag_name_key: &chacha20poly1 tag_names .iter() .map(|tag_name| - if tag_name.starts_with("~") { + if tag_name.starts_with('~') { TagName::OfPlain(encrypt_as_searchable( &tag_name.as_bytes()[1..], tag_name_key, tags_hmac_key)) } else { @@ -105,7 +105,7 @@ pub(super) fn encrypt_tags(tags: &HashMap, tags .iter() .map(|(tag_name, tag_value)| - if tag_name.starts_with("~") { + if tag_name.starts_with('~') { // '~' character on start is skipped. Tag::PlainText( encrypt_as_searchable(&tag_name.as_bytes()[1..], tag_name_key, tags_hmac_key), diff --git a/libindy/src/services/wallet/language.rs b/libindy/src/services/wallet/language.rs index 28d6e8001f..8a4504989d 100644 --- a/libindy/src/services/wallet/language.rs +++ b/libindy/src/services/wallet/language.rs @@ -14,11 +14,11 @@ pub enum TagName { impl TagName { fn from(s: String) -> IndyResult { - if s.is_empty() || s.starts_with("~") && s.len() == 1 { + if s.is_empty() || s.starts_with('~') && s.len() == 1 { return Err(err_msg(IndyErrorKind::WalletQueryError, "Tag name must not be empty")); } - if s.starts_with("~") { + if s.starts_with('~') { Ok(TagName::PlainTagName(s.into_bytes()[1..].to_vec())) } else { Ok(TagName::EncryptedTagName(s.into_bytes())) diff --git a/libindy/src/services/wallet/storage/default/mod.rs b/libindy/src/services/wallet/storage/default/mod.rs index 1aba78369f..b35c787586 100644 --- a/libindy/src/services/wallet/storage/default/mod.rs +++ b/libindy/src/services/wallet/storage/default/mod.rs @@ -297,7 +297,7 @@ impl WalletStorage for SQLiteStorage { let item = match res { Ok(entity) => entity, - Err(rusqlite::Error::QueryReturnedNoRows) => return Err(err_msg(IndyErrorKind::WalletItemNotFound, "Walelt item not found")), + Err(rusqlite::Error::QueryReturnedNoRows) => return Err(err_msg(IndyErrorKind::WalletItemNotFound, "Wallet item not found")), Err(err) => return Err(IndyError::from(err)) }; @@ -391,8 +391,8 @@ impl WalletStorage for SQLiteStorage { match res { Ok(1) => Ok(()), - Ok(0) => return Err(err_msg(IndyErrorKind::WalletItemNotFound, "Item to update not found")), - Ok(_) => return Err(err_msg(IndyErrorKind::InvalidState, "More than one row update. Seems wallet structure is inconsistent")), + Ok(0) => Err(err_msg(IndyErrorKind::WalletItemNotFound, "Item to update not found")), + Ok(_) => Err(err_msg(IndyErrorKind::InvalidState, "More than one row update. Seems wallet structure is inconsistent")), Err(err) => Err(err.into()), } } @@ -531,8 +531,8 @@ impl WalletStorage for SQLiteStorage { match res { Ok(entity) => Ok(entity), - Err(rusqlite::Error::QueryReturnedNoRows) => return Err(err_msg(IndyErrorKind::WalletItemNotFound, "Wallet item not found")), - Err(err) => return Err(IndyError::from(err)) + Err(rusqlite::Error::QueryReturnedNoRows) => Err(err_msg(IndyErrorKind::WalletItemNotFound, "Wallet item not found")), + Err(err) => Err(IndyError::from(err)) } } @@ -650,7 +650,7 @@ impl WalletStorageType for SQLiteStorageType { let db_file_path = SQLiteStorageType::_db_path(id, config.as_ref()); if !db_file_path.exists() { - return Err(err_msg(IndyErrorKind::WalletNotFound, "Wallet storage file isn't found")); + return Err(err_msg(IndyErrorKind::WalletNotFound, format!("Wallet storage file isn't found: {:?}", db_file_path))); } std::fs::remove_dir_all(db_file_path.parent().unwrap())?; @@ -694,7 +694,7 @@ impl WalletStorageType for SQLiteStorageType { let db_path = SQLiteStorageType::_db_path(id, config.as_ref()); if db_path.exists() { - return Err(err_msg(IndyErrorKind::WalletAlreadyExists, "Wallet database file already exists")); + return Err(err_msg(IndyErrorKind::WalletAlreadyExists, format!("Wallet database file already exists: {:?}", db_path))); } fs::DirBuilder::new() diff --git a/libindy/tests/anoncreds.rs b/libindy/tests/anoncreds.rs index f0d7116504..af9f38319d 100644 --- a/libindy/tests/anoncreds.rs +++ b/libindy/tests/anoncreds.rs @@ -27,21 +27,16 @@ extern crate serde; #[macro_use] mod utils; -use utils::{wallet, anoncreds, blob_storage}; -use utils::anoncreds::{COMMON_MASTER_SECRET, CREDENTIAL1_ID, CREDENTIAL2_ID, CREDENTIAL3_ID, ANONCREDS_WALLET_CONFIG}; +use utils::{wallet, anoncreds}; +use utils::anoncreds::{COMMON_MASTER_SECRET, CREDENTIAL1_ID, ANONCREDS_WALLET_CONFIG}; use indy::ErrorCode; -use utils::inmem_wallet::InmemWallet; use utils::constants::*; use utils::domain::anoncreds::schema::{Schema, AttributeNames, MAX_ATTRIBUTES_COUNT}; use utils::domain::anoncreds::credential_definition::CredentialDefinition; -use utils::domain::anoncreds::revocation_registry_definition::RevocationRegistryDefinition; use utils::domain::anoncreds::credential::CredentialInfo; use utils::domain::anoncreds::credential_for_proof_request::{CredentialsForProofRequest, RequestedCredential}; -use utils::domain::anoncreds::proof::Proof; -use utils::domain::anoncreds::revocation_state::RevocationState; -use utils::domain::anoncreds::revocation_registry::RevocationRegistry; use std::collections::HashSet; @@ -3701,2219 +3696,3 @@ mod medium_cases { } } } - -mod demos { - use super::*; - - #[test] - fn anoncreds_works_for_single_issuer_single_prover() { - utils::setup(); - - //1. Create Issuer wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Create Prover wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Issuer creates Schema and Credential Definition - let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //5. Issuance credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json); - - //6. Proof request - let proof_req_json = r#"{ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes":{ - "attr1_referent":{ - "name":"name" - }, - "attr2_referent":{ - "name":"sex" - }, - "attr3_referent":{"name":"phone"} - }, - "requested_predicates":{ - "predicate1_referent":{"name":"age","p_type":">=","p_value":18} - } - }"#; - - //7. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //8. Prover creates Proof - let self_attested_value = "8-800-300"; - let requested_credentials_json = format!(r#"{{ - "self_attested_attributes":{{"attr3_referent":"{}"}}, - "requested_attributes":{{ - "attr1_referent":{{ "cred_id":"{}", "revealed":true }}, - "attr2_referent":{{ "cred_id":"{}", "revealed":false }} - }}, - "requested_predicates":{{ - "predicate1_referent":{{ "cred_id":"{}" }} - }} - }}"#, self_attested_value, credential.referent, credential.referent, credential.referent); - - let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); - let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &cred_defs_json, - &rev_states_json).unwrap(); - - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //9. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - assert_eq!(0, proof.requested_proof.unrevealed_attrs.get("attr2_referent").unwrap().sub_proof_index); - assert_eq!(self_attested_value, proof.requested_proof.self_attested_attrs.get("attr3_referent").unwrap()); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &cred_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_plugged_wallet() { - utils::setup(); - InmemWallet::cleanup(); - - //1. Registers new wallet type - wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); - - //2. Creates and opens Issuer wallet - let issuer_wallet_config = json!({ - "id": "custom_issuer_wallet", - "storage_type": INMEM_TYPE, - }).to_string(); - - wallet::create_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); - let issuer_wallet_handle = wallet::open_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); - - //3. Creates and opens Prover wallet - let prover_wallet_config = json!({ - "id": "custom_prover_wallet", - "storage_type": INMEM_TYPE, - }).to_string(); - - wallet::create_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); - let prover_wallet_handle = wallet::open_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); - - //4. Issuer creates Schema and Credential Definition - let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //5. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //6. Issuance credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json); - - //7. Proof request - let proof_req_json = r#"{ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes":{ - "attr1_referent":{ - "name":"name" - } - }, - "requested_predicates":{} - }"#; - - //8. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //9. Prover creates Proof - let requested_credentials_json = format!(r#"{{ - "self_attested_attributes":{{}}, - "requested_attributes":{{ - "attr1_referent":{{ "cred_id":"{}", "revealed":true }} - }}, - "requested_predicates":{{ - }} - }}"#, credential.referent); - - let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); - let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &cred_defs_json, - &rev_states_json).unwrap(); - - //10. Verifier verifies Proof - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &cred_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(prover_wallet_handle).unwrap(); - wallet::close_wallet(issuer_wallet_handle).unwrap(); - InmemWallet::cleanup(); - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_multiple_issuer_single_prover() { - utils::setup(); - - //1. Issuer1 creates wallet, gets wallet handles - let issuer_gvt_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Issuer2 creates wallet, gets wallet handles - let issuer_xyz_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Prover creates wallet, gets wallet handles - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //4. Issuer1 creates GVT Schema and Credential Definition - let (gvt_schema_id, gvt_schema, - gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_gvt_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //5. Issuer2 creates XYZ Schema and Credential Definition - let (xyz_schema_id, xyz_schema, - xyz_cred_def_id, xyz_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_xyz_wallet_handle, - DID_MY2, - XYZ_SCHEMA_NAME, - XYZ_SCHEMA_ATTRIBUTES); - - //6. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //7. Issuer1 issue GVT Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_gvt_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &gvt_cred_def_id, - &gvt_cred_def_json); - - //8. Issuer2 issue XYZ Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_xyz_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::xyz_credential_values_json(), - &xyz_cred_def_id, - &xyz_cred_def_json); - - //9. Proof request - let proof_req_json = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name", - "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) - }) , - "attr2_referent": json!({ - "name":"status", - "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), - "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), - }), - }).to_string(); - - //10. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - - let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); - let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); - let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate2_referent"); - - //11. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), - "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), - "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) - }) - }).to_string(); - - let schemas_json = json!({ - gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), - xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), - xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() - }).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //12. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - assert_eq!("partial", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(prover_wallet_handle).unwrap(); - wallet::close_wallet(issuer_gvt_wallet_handle).unwrap(); - wallet::close_wallet(issuer_xyz_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_single_issuer_multiple_credentials_single_prover() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handles - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handles - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Issuer creates GVT Schema and Credential Definition - let (gvt_schema_id, gvt_schema, - gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //4. Issuer creates XYZ Schema and Credential Definition - let (xyz_schema_id, xyz_schema, - xyz_cred_def_id, xyz_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - XYZ_SCHEMA_NAME, - XYZ_SCHEMA_ATTRIBUTES); - - //5. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //6. Issuer issue GVT Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &gvt_cred_def_id, - &gvt_cred_def_json); - - //7. Issuer issue XYZ Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::xyz_credential_values_json(), - &xyz_cred_def_id, - &xyz_cred_def_json); - - //8. Proof Request - let proof_req_json = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name", - "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) - }) , - "attr2_referent": json!({ - "name":"status", - "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), - "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), - }), - }).to_string(); - - //9. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - - let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); - let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); - let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate2_referent"); - - //10. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), - "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), - "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) - }) - }).to_string(); - - let schemas_json = json!({ - gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), - xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), - xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() - }).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //11. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - assert_eq!("partial", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(prover_wallet_handle).unwrap(); - wallet::close_wallet(issuer_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_revocation_proof_issuance_by_demand() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3 Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - - //5. Issuance Credential - let (cred_rev_id, revoc_reg_delta_json) = anoncreds::multi_steps_create_revocation_credential( - COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); - - //6. Prover gets Credentials for Proof Request - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":80, "to":100 }) - }).to_string(); - - //7. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //8. Prover creates RevocationState - let timestamp = 100; - let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp, - &cred_rev_id).unwrap(); - - //9. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() - }) - }).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_request, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //10. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_revocation_proof_issuance_by_default() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3 Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, revoc_reg_entry_json, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#); - - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( - COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - - //5. Proof Request - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":80, "to":100 }) - }).to_string(); - - //6. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //7. Prover creates Revocation State - let timestamp = 100; - - let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_entry_json, - timestamp, - &cred_rev_id).unwrap(); - - //8. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() - }) - }).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_request, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //9. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_entry_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn verifier_verify_proof_works_for_proof_does_not_correspond_proof_request_attr_and_predicate() { - utils::setup(); - - // 1. Creates wallet, gets wallet handle - let wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // 2. Issuer creates Schema and Credential Definition - let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - // 3. Prover creates Master Secret - anoncreds::prover_create_master_secret(wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - // 4. Issuer issue Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - wallet_handle, - wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json); - - // 5. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &anoncreds::proof_request_attr()).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - // 6. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) - }), - "requested_predicates": json!({ }) - }).to_string(); - - let schemas_json = json!({ - schema_id: serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(wallet_handle, - &anoncreds::proof_request_attr(), - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - // 7. Verifier verifies proof - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let res = anoncreds::verifier_verify_proof(&anoncreds::proof_request_attr_and_predicate(), - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json); - assert_code!(ErrorCode::CommonInvalidStructure, res); - - wallet::close_wallet(wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_requested_attribute_in_upper_case() { - utils::setup(); - - //1. Create Issuer wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Create Prover wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Issuer creates Schema and Credential Definition - let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //5. Issuer issue Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json); - - //6. Prover gets Credentials for Proof Request - let proof_req_json = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":" NAME" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"AGE", "p_type":">=", "p_value":18 }) - }) - }).to_string(); - - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //7. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential.referent }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id: serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //8. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential() { - utils::setup(); - - // Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Prover1 creates wallet, gets wallet handle - let prover1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Prover2 creates wallet, gets wallet handle - let prover2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Prover3 creates wallet, gets wallet handle - let prover3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3 Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - // ISSUANCE CREDENTIAL FOR PROVER1 - - // Prover1 creates Master Secret - let prover1_master_secret_id = "prover1_master_secret"; - anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id).unwrap(); - - let (prover1_cred_rev_id, revoc_reg_delta1_json) = anoncreds::multi_steps_create_revocation_credential( - prover1_master_secret_id, - prover1_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); - - // ISSUANCE CREDENTIAL FOR PROVER2 - // Prover2 creates Master Secret - let prover2_master_secret_id = "prover2_master_secret"; - anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id).unwrap(); - - let (prover2_cred_rev_id, revoc_reg_delta2_json) = anoncreds::multi_steps_create_revocation_credential( - prover2_master_secret_id, - prover2_wallet_handle, - issuer_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::gvt2_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); - - // Issuer merge Revocation Registry Deltas - let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta1_json, - &revoc_reg_delta2_json).unwrap(); - - //ISSUANCE CREDENTIAL FOR PROVER3 - // Prover3 creates Master Secret - let prover3_master_secret_id = "prover3_master_secret"; - anoncreds::prover_create_master_secret(prover3_wallet_handle, prover3_master_secret_id).unwrap(); - - let (prover3_cred_rev_id, revoc_reg_delta3_json) = anoncreds::multi_steps_create_revocation_credential( - prover3_master_secret_id, - prover3_wallet_handle, - issuer_wallet_handle, - CREDENTIAL3_ID, - &anoncreds::gvt3_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta3_json = revoc_reg_delta3_json.unwrap(); - - // Issuer merge Revocation Registry Deltas - let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta_json, &revoc_reg_delta3_json).unwrap(); - - //PROVER1 PROVING REQUEST - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":80, "to":100 }) - }).to_string(); - - // Prover1 gets Credentials for Proof Request - let prover1_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request).unwrap(); - let prover1_credential = anoncreds::get_credential_for_attr_referent(&prover1_credentials_json, "attr1_referent"); - - // Prover1 creates RevocationState - let timestamp = 80; - let prover1_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp, - &prover1_cred_rev_id).unwrap(); - - // Prover1 creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&prover1_rev_state_json).unwrap() - }) - }).to_string(); - - let proof1_json = anoncreds::prover_create_proof(prover1_wallet_handle, - &proof_request, - &requested_credentials_json, - prover1_master_secret_id, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - // Verifier verifies proof from Prover1 - let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof1_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - - //PROVER2 PROVING REQUEST - - // Prover2 gets Credentials for Proof Request - let prover2_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover2_wallet_handle, &proof_request).unwrap(); - let prover2_credential = anoncreds::get_credential_for_attr_referent(&prover2_credentials_json, "attr1_referent"); - - // Prover2 creates RevocationState - let timestamp = 90; - let prover2_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp, - &prover2_cred_rev_id).unwrap(); - - // Prover2 creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&prover2_rev_state_json).unwrap() - }) - }).to_string(); - - let proof2_json = anoncreds::prover_create_proof(prover2_wallet_handle, - &proof_request, - &requested_credentials_json, - prover2_master_secret_id, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - // Verifier verifies proof from Prover2 - let proof: Proof = serde_json::from_str(&proof2_json).unwrap(); - assert_eq!("Alexander", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof2_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - - // PROVING REQUEST - - // Prover3 gets Credentials for Proof Request - let prover3_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover3_wallet_handle, &proof_request).unwrap(); - let prover3_credential = anoncreds::get_credential_for_attr_referent(&prover3_credentials_json, "attr1_referent"); - - // Prover3 creates RevocationState - let timestamp = 100; - let prover3_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp, - &prover3_cred_rev_id).unwrap(); - - // Prover3 creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&prover3_rev_state_json).unwrap() - }) - }).to_string(); - - let proof3_json = anoncreds::prover_create_proof(prover3_wallet_handle, - &proof_request, - &requested_credentials_json, - prover3_master_secret_id, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - // Verifier verifies proof from Prover2 - let proof: Proof = serde_json::from_str(&proof3_json).unwrap(); - assert_eq!("Artem", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof3_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover1_wallet_handle).unwrap(); - wallet::close_wallet(prover2_wallet_handle).unwrap(); - wallet::close_wallet(prover3_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_twice_entry_of_attribute_from_different_credential() { - utils::setup(); - - //1. Issuer1 creates wallet, gets wallet handles - let issuer_gvt_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Issuer2 creates wallet, gets wallet handles - let issuer_abc_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Prover creates wallet, gets wallet handles - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //4. Issuer creates Schema and Credential Definition - let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_gvt_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES); - - //5. Issuer creates Schema and Credential Definition - let (abc_schema_id, abc_schema, abc_cred_def_id, abc_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_abc_wallet_handle, - ISSUER_DID, - "abc", - r#"["name", "second_name", "experience"]"#); - - //6. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //7. Issuer1 issue GVT Credential for Prover - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_gvt_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &gvt_cred_def_id, - &gvt_cred_def_json); - - //8. Issuer2 issue ABC Credential for Prover - // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 - let abc_cred_values = r#"{ - "name": {"raw":"Alexander", "encoded": "126328542632549235769221"}, - "second_name": {"raw":"Park", "encoded": "42935129364832492914638245934"}, - "experience": {"raw":"5", "encoded": "5"} - }"#; - - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_abc_wallet_handle, - CREDENTIAL2_ID, - abc_cred_values, - &abc_cred_def_id, - &abc_cred_def_json); - - //9. Verifier asks attributes with same name but from different Credentials - let proof_req_json = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name", - "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) - }) , - "attr2_referent": json!({ - "name":"name", - "restrictions": json!({ "cred_def_id": abc_cred_def_id }) - }) - }), - "requested_predicates": json!({}), - }).to_string(); - - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - - let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); - - //10. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), - "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) - }), - "requested_predicates": json!({}) - }).to_string(); - - let schemas_json = json!({ - gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), - abc_schema_id: serde_json::from_str::(&abc_schema).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), - abc_cred_def_id: serde_json::from_str::(&abc_cred_def_json).unwrap() - }).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - let proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //11. Verifier verifies proof - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - assert_eq!("Alexander", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); - - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(prover_wallet_handle).unwrap(); - wallet::close_wallet(issuer_gvt_wallet_handle).unwrap(); - wallet::close_wallet(issuer_abc_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - fn anoncreds_works_for_twice_entry_of_credential_for_different_witness() { - utils::setup(); - - // Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Prover1 creates wallet, gets wallet handle - let prover1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Prover2 creates wallet, gets wallet handle - let prover2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - // Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - // ISSUANCE CREDENTIAL FOR PROVER1 - - // Prover1 creates Master Secret - let prover1_master_secret_id = "prover1_master_secret"; - anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id).unwrap(); - - let timestamp1 = time::get_time().sec as u64; - - let (prover1_cred_rev_id, revoc_reg_delta1_json) = anoncreds::multi_steps_create_revocation_credential( - prover1_master_secret_id, - prover1_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); - - // ISSUANCE CREDENTIAL FOR PROVER2 - // Prover2 creates Master Secret - let prover2_master_secret_id = "prover2_master_secret"; - anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id).unwrap(); - - let timestamp2 = time::get_time().sec as u64 + 100; - - let (_, revoc_reg_delta2_json) = anoncreds::multi_steps_create_revocation_credential( - prover2_master_secret_id, - prover2_wallet_handle, - issuer_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::gvt2_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); - - // Issuer merge Revocation Registry Deltas - let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta1_json, &revoc_reg_delta2_json).unwrap(); - - //PROVER1 PROVING REQUEST - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name", - "non_revoked": json!({ "to":timestamp1 + 1 }) - }), - "attr2_referent": json!({ - "name":"name", - "non_revoked": json!({ "from":timestamp1, "to":timestamp2 + 1 }) - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":timestamp1, "to":timestamp2 }) - }).to_string(); - - // Prover1 gets Credentials for Proof Request - let prover1_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request).unwrap(); - let credentials: CredentialsForProofRequest = serde_json::from_str(&prover1_credentials_json).unwrap(); - - let prover1_credential = credentials.attrs.get("attr1_referent").unwrap()[0].clone(); - let prover2_credential = credentials.attrs.get("attr2_referent").unwrap()[0].clone(); - - assert_ne!(prover1_credential.interval, prover2_credential.interval); - - // Prover1 creates RevocationState for Timestamp 1 - let prover1_rev_state_1_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta1_json, - timestamp1, - &prover1_cred_rev_id).unwrap(); - - // Prover1 creates RevocationState for Timestamp 2 - let prover1_rev_state_2_json = anoncreds::update_revocation_state(blob_storage_reader_handle, - &prover1_rev_state_1_json, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp2, - &prover1_cred_rev_id).unwrap(); - - // Prover1 creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": prover1_credential.cred_info.referent, "timestamp": timestamp1, "revealed":true }), - "attr2_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2 }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp1.to_string(): serde_json::from_str::(&prover1_rev_state_1_json).unwrap(), - timestamp2.to_string(): serde_json::from_str::(&prover1_rev_state_2_json).unwrap() - }) - }).to_string(); - - let proof1_json = anoncreds::prover_create_proof(prover1_wallet_handle, - &proof_request, - &requested_credentials_json, - prover1_master_secret_id, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - // Verifier verifies proof from Prover1 - let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); - assert_eq!(2, proof.requested_proof.revealed_attrs.len()); - assert_eq!(2, proof.identifiers.len()); - - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); - assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); - - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp1.to_string(): serde_json::from_str::(&revoc_reg_delta1_json).unwrap(), - timestamp2.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof1_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover1_wallet_handle).unwrap(); - wallet::close_wallet(prover2_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[test] - #[ignore] //FIXME - fn anoncreds_works_for_misused_witness() { - //??? - // ignore requested timestamp in proof request - // - provide valid proof for invalid time - // - provide hacked proof: specify requested timestamp, actually use invalid TS - unimplemented!(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_on_demand_revocation_strategy_revoke_credential() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3 Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - //4. Issuance Credential for Prover - // Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - let (cred_rev_id, revoc_reg_delta_json) = anoncreds::multi_steps_create_revocation_credential( - COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); - - //5. Prover gets Credentials for Proof Request - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":80, "to":100 }) - }).to_string(); - - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //6. Prover creates RevocationState - let timestamp = 100; - let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &revoc_reg_delta_json, - timestamp, - &cred_rev_id).unwrap(); - - //7. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id: serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() - }) - }).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_request, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - //8. Verifier verifies proof before it will be revoked - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - //9. Issuer revokes credential - let revoc_reg_delta_json = anoncreds::issuer_revoke_credential(issuer_wallet_handle, - blob_storage_reader_handle, - &rev_reg_id, - &cred_rev_id).unwrap(); - - //10. Verifier verifies proof after that was revoked - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(!valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_by_default_revocation_strategy_revoke_credential() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3 Issuer creates Schema, Credential Definition and Revocation Registry - let (schema_id, schema_json, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, rev_reg_entry_json, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - &anoncreds::issuance_by_default_rev_reg_config()); - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //5. Issuance Credential for Prover - let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( - COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle, - ); - - //6. Prover gets Credentials for Proof Request - let proof_request = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "attr1_referent": json!({ - "name":"name" - }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) - }), - "non_revoked": json!({ "from":80, "to":100 }) - }).to_string(); - - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); - let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); - - //7. Prover creates RevocationState - let timestamp = 100; - let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, - &revoc_reg_def_json, - &rev_reg_entry_json, - timestamp, - &cred_rev_id).unwrap(); - - //8. Prover creates Proof - let requested_credentials_json = json!({ - "self_attested_attributes": json!({}), - "requested_attributes": json!({ - "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) - }), - "requested_predicates": json!({ - "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) - }) - }).to_string(); - - let schemas_json = json!({ - schema_id: serde_json::from_str::(&schema_json).unwrap() - }).to_string(); - - let credential_defs_json = json!({ - cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() - }).to_string(); - - let rev_states_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() - }) - }).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_request, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &credential_defs_json, - &rev_states_json).unwrap(); - - //9. Verifier verifies proof before it will be revoked - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&rev_reg_entry_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - //10. Issuer revokes credential - let revoc_reg_delta_json = anoncreds::issuer_revoke_credential(issuer_wallet_handle, - blob_storage_reader_handle, - &rev_reg_id, - &cred_rev_id).unwrap(); - - //11. Verifier verifies proof after that was revoked - let rev_reg_defs_json = json!({ - rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() - }).to_string(); - - let rev_regs_json = json!({ - rev_reg_id.clone(): json!({ - timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() - }) - }).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_request, - &proof_json, - &schemas_json, - &credential_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(!valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Prover creates wallet, gets wallet handle - let prover_2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //4. Prover creates wallet, gets wallet handle - let prover_3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //5 Issuer creates Schema, Credential Definition and Revocation Registry - let (_, _, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - //6. Prover1 creates Master Secret - let prover_1_master_secret = "prover1_master_secret"; - anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret).unwrap(); - - - anoncreds::multi_steps_create_revocation_credential(prover_1_master_secret, - prover_1_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle); - - //7. Issuance Credential for Prover2 - // Prover2 creates Master Secret - let prover_2_master_secret = "prover2_master_secret"; - anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret).unwrap(); - - anoncreds::multi_steps_create_revocation_credential(prover_2_master_secret, - prover_2_wallet_handle, - issuer_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::gvt2_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle); - - //8. Issuance Credential for Prover3 - let prover_3_master_secret = "prover_3_master_secret"; - anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret).unwrap(); - - let cred_offer_json = anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); - - let (cred_req_json, _) = anoncreds::prover_create_credential_req(prover_3_wallet_handle, - DID_MY2, - &cred_offer_json, - &cred_def_json, - prover_3_master_secret).unwrap(); - - let res = anoncreds::issuer_create_credential(issuer_wallet_handle, - &cred_offer_json, - &cred_req_json, - &anoncreds::gvt_credential_values_json(), - Some(&rev_reg_id), - Some(blob_storage_reader_handle)); - assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_1_wallet_handle).unwrap(); - wallet::close_wallet(prover_2_wallet_handle).unwrap(); - wallet::close_wallet(prover_3_wallet_handle).unwrap(); - - utils::tear_down(); - } - - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Prover creates wallet, gets wallet handle - let prover_1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Prover creates wallet, gets wallet handle - let prover_2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //4. Prover creates wallet, gets wallet handle - let prover_3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //5 Issuer creates Schema, Credential Definition and Revocation Registry - let (_, _, - cred_def_id, cred_def_json, - rev_reg_id, revoc_reg_def_json, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#); - - // Prover1 creates Master Secret - let prover_1_master_secret = "prover1_master_secret"; - anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret).unwrap(); - - anoncreds::multi_steps_create_revocation_credential(prover_1_master_secret, - prover_1_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - &anoncreds::gvt_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle); - - //9. Issuance Credential for Prover2 - // Prover2 creates Master Secret - let prover_2_master_secret = "prover2_master_secret"; - anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret).unwrap(); - - anoncreds::multi_steps_create_revocation_credential(prover_2_master_secret, - prover_2_wallet_handle, - issuer_wallet_handle, - CREDENTIAL2_ID, - &anoncreds::gvt2_credential_values_json(), - &cred_def_id, - &cred_def_json, - &rev_reg_id, - &revoc_reg_def_json, - blob_storage_reader_handle); - - //10. Issuance Credential for Prover3 - let prover_3_master_secret = "prover_3_master_secret"; - anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret).unwrap(); - - let cred_offer_json = anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); - - let (cred_req_json, _) = anoncreds::prover_create_credential_req(prover_3_wallet_handle, - DID_MY2, - &cred_offer_json, - &cred_def_json, - prover_3_master_secret).unwrap(); - - let res = anoncreds::issuer_create_credential(issuer_wallet_handle, - &cred_offer_json, - &cred_req_json, - &anoncreds::gvt_credential_values_json(), - Some(&rev_reg_id), - Some(blob_storage_reader_handle)); - assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_1_wallet_handle).unwrap(); - wallet::close_wallet(prover_2_wallet_handle).unwrap(); - wallet::close_wallet(prover_3_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_revoke_not_issued_credential_id() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Issuer creates schema - let (_, schema_json) = anoncreds::issuer_create_schema(ISSUER_DID, - GVT_SCHEMA_NAME, - SCHEMA_VERSION, - GVT_SCHEMA_ATTRIBUTES).unwrap(); - - //3. Issuer creates credential definition - let (cred_def_id, _) = anoncreds::issuer_create_credential_definition(issuer_wallet_handle, - ISSUER_DID, - &schema_json, - TAG_1, - None, - Some(&anoncreds::revocation_cred_def_config())).unwrap(); - - //4. Issuer creates revocation registry for 2 Credentials - let tails_writer_config = anoncreds::tails_writer_config(); - let tails_writer_handle = blob_storage::open_writer("default", &tails_writer_config).unwrap(); - - let (rev_reg_id, _, _) = - anoncreds::issuer_create_and_store_revoc_reg(issuer_wallet_handle, - &ISSUER_DID, - None, - TAG_1, - &cred_def_id, - r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, - tails_writer_handle).unwrap(); - - let blob_storage_reader_handle = blob_storage::open_reader(TYPE, &tails_writer_config).unwrap(); - - //5. Issuer revokes Credential by not issued id - let cred_rev_id = "100"; - let res = anoncreds::issuer_revoke_credential(issuer_wallet_handle, blob_storage_reader_handle, &rev_reg_id, cred_rev_id); - assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - - utils::tear_down(); - } - - #[cfg(feature = "revocation_tests")] - #[test] - fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_revoke_not_issued_credential_id() { - utils::setup(); - - //1. Issuer creates wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2 Issuer creates Schema, Credential Definition and Revocation Registry - let (_, _, - _, _, - rev_reg_id, _, _, - blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, - ISSUER_DID, - GVT_SCHEMA_NAME, - GVT_SCHEMA_ATTRIBUTES, - r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); - - //3. Issuer revokes Credential by not issued id - let cred_rev_id = 10.to_string(); - let res = anoncreds::issuer_revoke_credential(issuer_wallet_handle, blob_storage_reader_handle, &rev_reg_id, &cred_rev_id); - assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - - utils::tear_down(); - } - - - #[test] - fn anoncreds_works_for_multiple_requested_predicates_from_one_credential() { - utils::setup(); - - //1. Create Issuer wallet, gets wallet handle - let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //2. Create Prover wallet, gets wallet handle - let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); - - //3. Issuer creates Schema and Credential Definition - let attr_names = r#"["task1", - "task2", - "task3", - "task4", - "task5", - "6*_task", - "7*_task", - "bonus", - "average", - "aggregated", - "total"]"#; - let (schema_id, schema_json, cred_def_id, cred_def_json) = - anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, - ISSUER_DID, - "test", - attr_names); - - //4. Prover creates Master Secret - anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); - - //5. Issuance credential for Prover - let cred_values = r#"{ - "task1": {"raw":"8", "encoded": "8"}, - "task2": {"raw":"8", "encoded": "8"}, - "task3": {"raw":"10", "encoded": "10"}, - "task4": {"raw":"9", "encoded": "9"}, - "task5": {"raw":"7", "encoded": "7"}, - "6*_task": {"raw":"8", "encoded": "8"}, - "7*_task": {"raw":"9", "encoded": "9"}, - "bonus": {"raw":"5", "encoded": "5"}, - "average": {"raw":"9", "encoded": "9"}, - "aggregated": {"raw":"9", "encoded": "9"}, - "total": {"raw":"77", "encoded": "77"} - }"#; - - anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, - prover_wallet_handle, - issuer_wallet_handle, - CREDENTIAL1_ID, - cred_values, - &cred_def_id, - &cred_def_json); - - //6. Proof request - let proof_req_json = r#"{ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes":{}, - "requested_predicates":{ - "predicate1_referent":{"name":"task1","p_type":">=","p_value":5}, - "predicate2_referent":{"name":"task2","p_type":">=","p_value":7}, - "predicate3_referent":{"name":"task3","p_type":">=","p_value":7}, - "predicate4_referent":{"name":"task4","p_type":">=","p_value":8}, - "predicate5_referent":{"name":"task5","p_type":">=","p_value":5}, - "predicate6_referent":{"name":"6*_task","p_type":">=","p_value":7}, - "predicate7_referent":{"name":"7*_task","p_type":">=","p_value":7}, - "predicate8_referent":{"name":"bonus","p_type":">=","p_value":3}, - "predicate9_referent":{"name":"average","p_type":">=","p_value":8}, - "predicate10_referent":{"name":"aggregated","p_type":">=","p_value":7}, - "predicate11_referent":{"name":"total","p_type":">=","p_value":70} - } - }"#; - - //7. Prover gets Credentials for Proof Request - let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); - let credential = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); - - //8. Prover creates Proof - let requested_credentials_json = format!(r#"{{ - "self_attested_attributes":{{}}, - "requested_attributes":{{}}, - "requested_predicates":{{ - "predicate1_referent":{{ "cred_id":"{}" }}, - "predicate2_referent":{{ "cred_id":"{}" }}, - "predicate3_referent":{{ "cred_id":"{}" }}, - "predicate4_referent":{{ "cred_id":"{}" }}, - "predicate5_referent":{{ "cred_id":"{}" }}, - "predicate6_referent":{{ "cred_id":"{}" }}, - "predicate7_referent":{{ "cred_id":"{}" }}, - "predicate8_referent":{{ "cred_id":"{}" }}, - "predicate9_referent":{{ "cred_id":"{}" }}, - "predicate10_referent":{{ "cred_id":"{}" }}, - "predicate11_referent":{{ "cred_id":"{}" }} - }} - }}"#, credential.referent, credential.referent, credential.referent, credential.referent, credential.referent, - credential.referent, credential.referent, credential.referent, credential.referent, credential.referent, credential.referent); - - let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); - let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); - let rev_states_json = json!({}).to_string(); - - let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, - &proof_req_json, - &requested_credentials_json, - COMMON_MASTER_SECRET, - &schemas_json, - &cred_defs_json, - &rev_states_json).unwrap(); - - let _proof: Proof = serde_json::from_str(&proof_json).unwrap(); - - //9. Verifier verifies proof - let rev_reg_defs_json = json!({}).to_string(); - let rev_regs_json = json!({}).to_string(); - - let valid = anoncreds::verifier_verify_proof(&proof_req_json, - &proof_json, - &schemas_json, - &cred_defs_json, - &rev_reg_defs_json, - &rev_regs_json).unwrap(); - assert!(valid); - - wallet::close_wallet(issuer_wallet_handle).unwrap(); - wallet::close_wallet(prover_wallet_handle).unwrap(); - - utils::tear_down(); - } -} diff --git a/libindy/tests/anoncreds_demos.rs b/libindy/tests/anoncreds_demos.rs new file mode 100644 index 0000000000..0f5254f95c --- /dev/null +++ b/libindy/tests/anoncreds_demos.rs @@ -0,0 +1,2259 @@ +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate named_type_derive; + +#[macro_use] +extern crate derivative; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate serde_json; + +extern crate byteorder; +extern crate indyrs as indy; +extern crate indyrs as api; +extern crate indy_crypto; +extern crate uuid; +extern crate named_type; +extern crate rmp_serde; +extern crate rust_base58; +extern crate time; +extern crate serde; + +#[macro_use] +mod utils; + +use utils::{wallet, anoncreds}; +use utils::anoncreds::{COMMON_MASTER_SECRET, CREDENTIAL1_ID, CREDENTIAL2_ID, CREDENTIAL3_ID}; + +use indy::ErrorCode; +use utils::inmem_wallet::InmemWallet; +use utils::constants::*; + +use utils::domain::anoncreds::schema::Schema; +use utils::domain::anoncreds::credential_definition::CredentialDefinition; +use utils::domain::anoncreds::revocation_registry_definition::RevocationRegistryDefinition; +use utils::domain::anoncreds::credential_for_proof_request::{CredentialsForProofRequest}; +use utils::domain::anoncreds::proof::Proof; +use utils::domain::anoncreds::revocation_state::RevocationState; +use utils::domain::anoncreds::revocation_registry::RevocationRegistry; + +mod demos { + use super::*; + + #[test] + fn anoncreds_works_for_single_issuer_single_prover() { + utils::setup(); + + //1. Create Issuer wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Create Prover wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json); + + //6. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + }, + "attr2_referent":{ + "name":"sex" + }, + "attr3_referent":{"name":"phone"} + }, + "requested_predicates":{ + "predicate1_referent":{"name":"age","p_type":">=","p_value":18} + } + }"#; + + //7. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates Proof + let self_attested_value = "8-800-300"; + let requested_credentials_json = format!(r#"{{ + "self_attested_attributes":{{"attr3_referent":"{}"}}, + "requested_attributes":{{ + "attr1_referent":{{ "cred_id":"{}", "revealed":true }}, + "attr2_referent":{{ "cred_id":"{}", "revealed":false }} + }}, + "requested_predicates":{{ + "predicate1_referent":{{ "cred_id":"{}" }} + }} + }}"#, self_attested_value, credential.referent, credential.referent, credential.referent); + + let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json).unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!(0, proof.requested_proof.unrevealed_attrs.get("attr2_referent").unwrap().sub_proof_index); + assert_eq!(self_attested_value, proof.requested_proof.self_attested_attrs.get("attr3_referent").unwrap()); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_plugged_wallet() { + utils::setup(); + InmemWallet::cleanup(); + + //1. Registers new wallet type + wallet::register_wallet_storage(INMEM_TYPE, false).unwrap(); + + //2. Creates and opens Issuer wallet + let issuer_wallet_config = json!({ + "id": "custom_issuer_wallet", + "storage_type": INMEM_TYPE, + }).to_string(); + + wallet::create_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); + let issuer_wallet_handle = wallet::open_wallet(&issuer_wallet_config, WALLET_CREDENTIALS).unwrap(); + + //3. Creates and opens Prover wallet + let prover_wallet_config = json!({ + "id": "custom_prover_wallet", + "storage_type": INMEM_TYPE, + }).to_string(); + + wallet::create_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); + let prover_wallet_handle = wallet::open_wallet(&prover_wallet_config, WALLET_CREDENTIALS).unwrap(); + + //4. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuance credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json); + + //7. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{ + "attr1_referent":{ + "name":"name" + } + }, + "requested_predicates":{} + }"#; + + //8. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //9. Prover creates Proof + let requested_credentials_json = format!(r#"{{ + "self_attested_attributes":{{}}, + "requested_attributes":{{ + "attr1_referent":{{ "cred_id":"{}", "revealed":true }} + }}, + "requested_predicates":{{ + }} + }}"#, credential.referent); + + let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json).unwrap(); + + //10. Verifier verifies Proof + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::close_wallet(issuer_wallet_handle).unwrap(); + InmemWallet::cleanup(); + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_multiple_issuer_single_prover() { + utils::setup(); + + //1. Issuer1 creates wallet, gets wallet handles + let issuer_gvt_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Issuer2 creates wallet, gets wallet handles + let issuer_xyz_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Prover creates wallet, gets wallet handles + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //4. Issuer1 creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, + gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_gvt_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //5. Issuer2 creates XYZ Schema and Credential Definition + let (xyz_schema_id, xyz_schema, + xyz_cred_def_id, xyz_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_xyz_wallet_handle, + DID_MY2, + XYZ_SCHEMA_NAME, + XYZ_SCHEMA_ATTRIBUTES); + + //6. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //7. Issuer1 issue GVT Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_gvt_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json); + + //8. Issuer2 issue XYZ Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_xyz_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::xyz_credential_values_json(), + &xyz_cred_def_id, + &xyz_cred_def_json); + + //9. Proof request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"status", + "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), + "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), + }), + }).to_string(); + + //10. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + + let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); + let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate2_referent"); + + //11. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), + "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() + }).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //12. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!("partial", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::close_wallet(issuer_gvt_wallet_handle).unwrap(); + wallet::close_wallet(issuer_xyz_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_single_issuer_multiple_credentials_single_prover() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handles + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handles + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Issuer creates GVT Schema and Credential Definition + let (gvt_schema_id, gvt_schema, + gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //4. Issuer creates XYZ Schema and Credential Definition + let (xyz_schema_id, xyz_schema, + xyz_cred_def_id, xyz_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + XYZ_SCHEMA_NAME, + XYZ_SCHEMA_ATTRIBUTES); + + //5. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //6. Issuer issue GVT Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json); + + //7. Issuer issue XYZ Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::xyz_credential_values_json(), + &xyz_cred_def_id, + &xyz_cred_def_json); + + //8. Proof Request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"status", + "restrictions": json!({ "cred_def_id": xyz_cred_def_id }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }), + "predicate2_referent": json!({ "name":"period", "p_type":">=", "p_value":5 }), + }), + }).to_string(); + + //9. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + + let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + let credential_for_predicate_1 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); + let credential_for_predicate_2 = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate2_referent"); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential_for_predicate_1.referent }), + "predicate2_referent": json!({ "cred_id": credential_for_predicate_2.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + xyz_schema_id: serde_json::from_str::(&xyz_schema).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + xyz_cred_def_id: serde_json::from_str::(&xyz_cred_def_json).unwrap() + }).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!("partial", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::close_wallet(issuer_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_issuance_by_demand() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + + //5. Issuance Credential + let (cred_rev_id, revoc_reg_delta_json) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); + + //6. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }).to_string(); + + //7. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //8. Prover creates RevocationState + let timestamp = 100; + let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &cred_rev_id).unwrap(); + + //9. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //10. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_issuance_by_default() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, revoc_reg_entry_json, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //5. Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }).to_string(); + + //6. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates Revocation State + let timestamp = 100; + + let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_entry_json, + timestamp, + &cred_rev_id).unwrap(); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_entry_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn verifier_verify_proof_works_for_proof_does_not_correspond_proof_request_attr_and_predicate() { + utils::setup(); + + // 1. Creates wallet, gets wallet handle + let wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // 2. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + // 3. Prover creates Master Secret + anoncreds::prover_create_master_secret(wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + // 4. Issuer issue Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + wallet_handle, + wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json); + + // 5. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(wallet_handle, &anoncreds::proof_request_attr()).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + // 6. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(wallet_handle, + &anoncreds::proof_request_attr(), + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + // 7. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let res = anoncreds::verifier_verify_proof(&anoncreds::proof_request_attr_and_predicate(), + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json); + assert_code!(ErrorCode::CommonInvalidStructure, res); + + wallet::close_wallet(wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_requested_attribute_in_upper_case() { + utils::setup(); + + //1. Create Issuer wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Create Prover wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Issuer creates Schema and Credential Definition + let (schema_id, schema_json, cred_def_id, cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuer issue Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json); + + //6. Prover gets Credentials for Proof Request + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":" NAME" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"AGE", "p_type":">=", "p_value":18 }) + }) + }).to_string(); + + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //8. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_revocation_proof_for_issuance_and_proving_three_credential() { + utils::setup(); + + // Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Prover1 creates wallet, gets wallet handle + let prover1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Prover2 creates wallet, gets wallet handle + let prover2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Prover3 creates wallet, gets wallet handle + let prover3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + // ISSUANCE CREDENTIAL FOR PROVER1 + + // Prover1 creates Master Secret + let prover1_master_secret_id = "prover1_master_secret"; + anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id).unwrap(); + + let (prover1_cred_rev_id, revoc_reg_delta1_json) = anoncreds::multi_steps_create_revocation_credential( + prover1_master_secret_id, + prover1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); + + // ISSUANCE CREDENTIAL FOR PROVER2 + // Prover2 creates Master Secret + let prover2_master_secret_id = "prover2_master_secret"; + anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id).unwrap(); + + let (prover2_cred_rev_id, revoc_reg_delta2_json) = anoncreds::multi_steps_create_revocation_credential( + prover2_master_secret_id, + prover2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta1_json, + &revoc_reg_delta2_json).unwrap(); + + //ISSUANCE CREDENTIAL FOR PROVER3 + // Prover3 creates Master Secret + let prover3_master_secret_id = "prover3_master_secret"; + anoncreds::prover_create_master_secret(prover3_wallet_handle, prover3_master_secret_id).unwrap(); + + let (prover3_cred_rev_id, revoc_reg_delta3_json) = anoncreds::multi_steps_create_revocation_credential( + prover3_master_secret_id, + prover3_wallet_handle, + issuer_wallet_handle, + CREDENTIAL3_ID, + &anoncreds::gvt3_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta3_json = revoc_reg_delta3_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta_json, &revoc_reg_delta3_json).unwrap(); + + //PROVER1 PROVING REQUEST + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }).to_string(); + + // Prover1 gets Credentials for Proof Request + let prover1_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request).unwrap(); + let prover1_credential = anoncreds::get_credential_for_attr_referent(&prover1_credentials_json, "attr1_referent"); + + // Prover1 creates RevocationState + let timestamp = 80; + let prover1_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover1_cred_rev_id).unwrap(); + + // Prover1 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover1_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover1_rev_state_json).unwrap() + }) + }).to_string(); + + let proof1_json = anoncreds::prover_create_proof(prover1_wallet_handle, + &proof_request, + &requested_credentials_json, + prover1_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + // Verifier verifies proof from Prover1 + let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof1_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + + //PROVER2 PROVING REQUEST + + // Prover2 gets Credentials for Proof Request + let prover2_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover2_wallet_handle, &proof_request).unwrap(); + let prover2_credential = anoncreds::get_credential_for_attr_referent(&prover2_credentials_json, "attr1_referent"); + + // Prover2 creates RevocationState + let timestamp = 90; + let prover2_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover2_cred_rev_id).unwrap(); + + // Prover2 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover2_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover2_rev_state_json).unwrap() + }) + }).to_string(); + + let proof2_json = anoncreds::prover_create_proof(prover2_wallet_handle, + &proof_request, + &requested_credentials_json, + prover2_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + // Verifier verifies proof from Prover2 + let proof: Proof = serde_json::from_str(&proof2_json).unwrap(); + assert_eq!("Alexander", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof2_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + + // PROVING REQUEST + + // Prover3 gets Credentials for Proof Request + let prover3_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover3_wallet_handle, &proof_request).unwrap(); + let prover3_credential = anoncreds::get_credential_for_attr_referent(&prover3_credentials_json, "attr1_referent"); + + // Prover3 creates RevocationState + let timestamp = 100; + let prover3_rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &prover3_cred_rev_id).unwrap(); + + // Prover3 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover3_credential.referent, "timestamp": timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&prover3_rev_state_json).unwrap() + }) + }).to_string(); + + let proof3_json = anoncreds::prover_create_proof(prover3_wallet_handle, + &proof_request, + &requested_credentials_json, + prover3_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + // Verifier verifies proof from Prover2 + let proof: Proof = serde_json::from_str(&proof3_json).unwrap(); + assert_eq!("Artem", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof3_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover1_wallet_handle).unwrap(); + wallet::close_wallet(prover2_wallet_handle).unwrap(); + wallet::close_wallet(prover3_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_twice_entry_of_attribute_from_different_credential() { + utils::setup(); + + //1. Issuer1 creates wallet, gets wallet handles + let issuer_gvt_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Issuer2 creates wallet, gets wallet handles + let issuer_abc_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Prover creates wallet, gets wallet handles + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //4. Issuer creates Schema and Credential Definition + let (gvt_schema_id, gvt_schema, gvt_cred_def_id, gvt_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_gvt_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES); + + //5. Issuer creates Schema and Credential Definition + let (abc_schema_id, abc_schema, abc_cred_def_id, abc_cred_def_json) = anoncreds::multi_steps_issuer_preparation(issuer_abc_wallet_handle, + ISSUER_DID, + "abc", + r#"["name", "second_name", "experience"]"#); + + //6. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //7. Issuer1 issue GVT Credential for Prover + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_gvt_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &gvt_cred_def_id, + &gvt_cred_def_json); + + //8. Issuer2 issue ABC Credential for Prover + // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786 + let abc_cred_values = r#"{ + "name": {"raw":"Alexander", "encoded": "126328542632549235769221"}, + "second_name": {"raw":"Park", "encoded": "42935129364832492914638245934"}, + "experience": {"raw":"5", "encoded": "5"} + }"#; + + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_abc_wallet_handle, + CREDENTIAL2_ID, + abc_cred_values, + &abc_cred_def_id, + &abc_cred_def_json); + + //9. Verifier asks attributes with same name but from different Credentials + let proof_req_json = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": gvt_cred_def_id }) + }) , + "attr2_referent": json!({ + "name":"name", + "restrictions": json!({ "cred_def_id": abc_cred_def_id }) + }) + }), + "requested_predicates": json!({}), + }).to_string(); + + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + + let credential_for_attr_1 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + let credential_for_attr_2 = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr2_referent"); + + //10. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential_for_attr_1.referent, "revealed":true }), + "attr2_referent": json!({ "cred_id": credential_for_attr_2.referent, "revealed":true }) + }), + "requested_predicates": json!({}) + }).to_string(); + + let schemas_json = json!({ + gvt_schema_id: serde_json::from_str::(&gvt_schema).unwrap(), + abc_schema_id: serde_json::from_str::(&abc_schema).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + gvt_cred_def_id: serde_json::from_str::(&gvt_cred_def_json).unwrap(), + abc_cred_def_id: serde_json::from_str::(&abc_cred_def_json).unwrap() + }).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + let proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //11. Verifier verifies proof + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!("Alexander", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); + + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(prover_wallet_handle).unwrap(); + wallet::close_wallet(issuer_gvt_wallet_handle).unwrap(); + wallet::close_wallet(issuer_abc_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + fn anoncreds_works_for_twice_entry_of_credential_for_different_witness() { + utils::setup(); + + // Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Prover1 creates wallet, gets wallet handle + let prover1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Prover2 creates wallet, gets wallet handle + let prover2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + // Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + // ISSUANCE CREDENTIAL FOR PROVER1 + + // Prover1 creates Master Secret + let prover1_master_secret_id = "prover1_master_secret"; + anoncreds::prover_create_master_secret(prover1_wallet_handle, prover1_master_secret_id).unwrap(); + + let timestamp1 = time::get_time().sec as u64; + + let (prover1_cred_rev_id, revoc_reg_delta1_json) = anoncreds::multi_steps_create_revocation_credential( + prover1_master_secret_id, + prover1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta1_json = revoc_reg_delta1_json.unwrap(); + + // ISSUANCE CREDENTIAL FOR PROVER2 + // Prover2 creates Master Secret + let prover2_master_secret_id = "prover2_master_secret"; + anoncreds::prover_create_master_secret(prover2_wallet_handle, prover2_master_secret_id).unwrap(); + + let timestamp2 = time::get_time().sec as u64 + 100; + + let (_, revoc_reg_delta2_json) = anoncreds::multi_steps_create_revocation_credential( + prover2_master_secret_id, + prover2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta2_json = revoc_reg_delta2_json.unwrap(); + + // Issuer merge Revocation Registry Deltas + let revoc_reg_delta_json = anoncreds::issuer_merge_revocation_registry_deltas(&revoc_reg_delta1_json, &revoc_reg_delta2_json).unwrap(); + + //PROVER1 PROVING REQUEST + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name", + "non_revoked": json!({ "to":timestamp1 + 1 }) + }), + "attr2_referent": json!({ + "name":"name", + "non_revoked": json!({ "from":timestamp1, "to":timestamp2 + 1 }) + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":timestamp1, "to":timestamp2 }) + }).to_string(); + + // Prover1 gets Credentials for Proof Request + let prover1_credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover1_wallet_handle, &proof_request).unwrap(); + let credentials: CredentialsForProofRequest = serde_json::from_str(&prover1_credentials_json).unwrap(); + + let prover1_credential = credentials.attrs.get("attr1_referent").unwrap()[0].clone(); + let prover2_credential = credentials.attrs.get("attr2_referent").unwrap()[0].clone(); + + assert_ne!(prover1_credential.interval, prover2_credential.interval); + + // Prover1 creates RevocationState for Timestamp 1 + let prover1_rev_state_1_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta1_json, + timestamp1, + &prover1_cred_rev_id).unwrap(); + + // Prover1 creates RevocationState for Timestamp 2 + let prover1_rev_state_2_json = anoncreds::update_revocation_state(blob_storage_reader_handle, + &prover1_rev_state_1_json, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp2, + &prover1_cred_rev_id).unwrap(); + + // Prover1 creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": prover1_credential.cred_info.referent, "timestamp": timestamp1, "revealed":true }), + "attr2_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": prover2_credential.cred_info.referent, "timestamp": timestamp2 }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id.clone(): serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id.clone(): serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp1.to_string(): serde_json::from_str::(&prover1_rev_state_1_json).unwrap(), + timestamp2.to_string(): serde_json::from_str::(&prover1_rev_state_2_json).unwrap() + }) + }).to_string(); + + let proof1_json = anoncreds::prover_create_proof(prover1_wallet_handle, + &proof_request, + &requested_credentials_json, + prover1_master_secret_id, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + // Verifier verifies proof from Prover1 + let proof: Proof = serde_json::from_str(&proof1_json).unwrap(); + assert_eq!(2, proof.requested_proof.revealed_attrs.len()); + assert_eq!(2, proof.identifiers.len()); + + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr1_referent").unwrap().raw); + assert_eq!("Alex", proof.requested_proof.revealed_attrs.get("attr2_referent").unwrap().raw); + + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp1.to_string(): serde_json::from_str::(&revoc_reg_delta1_json).unwrap(), + timestamp2.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof1_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover1_wallet_handle).unwrap(); + wallet::close_wallet(prover2_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[test] + #[ignore] //FIXME + fn anoncreds_works_for_misused_witness() { + //??? + // ignore requested timestamp in proof request + // - provide valid proof for invalid time + // - provide hacked proof: specify requested timestamp, actually use invalid TS + unimplemented!(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_on_demand_revocation_strategy_revoke_credential() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + //4. Issuance Credential for Prover + // Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + let (cred_rev_id, revoc_reg_delta_json) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + let revoc_reg_delta_json = revoc_reg_delta_json.unwrap(); + + //5. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }).to_string(); + + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //6. Prover creates RevocationState + let timestamp = 100; + let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &revoc_reg_delta_json, + timestamp, + &cred_rev_id).unwrap(); + + //7. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + //8. Verifier verifies proof before it will be revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + //9. Issuer revokes credential + let revoc_reg_delta_json = anoncreds::issuer_revoke_credential(issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + &cred_rev_id).unwrap(); + + //10. Verifier verifies proof after that was revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(!valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_revoke_credential() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3 Issuer creates Schema, Credential Definition and Revocation Registry + let (schema_id, schema_json, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, rev_reg_entry_json, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + &anoncreds::issuance_by_default_rev_reg_config()); + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance Credential for Prover + let (cred_rev_id, _) = anoncreds::multi_steps_create_revocation_credential( + COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle, + ); + + //6. Prover gets Credentials for Proof Request + let proof_request = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({ + "attr1_referent": json!({ + "name":"name" + }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"age", "p_type":">=", "p_value":18 }) + }), + "non_revoked": json!({ "from":80, "to":100 }) + }).to_string(); + + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_request).unwrap(); + let credential = anoncreds::get_credential_for_attr_referent(&credentials_json, "attr1_referent"); + + //7. Prover creates RevocationState + let timestamp = 100; + let rev_state_json = anoncreds::create_revocation_state(blob_storage_reader_handle, + &revoc_reg_def_json, + &rev_reg_entry_json, + timestamp, + &cred_rev_id).unwrap(); + + //8. Prover creates Proof + let requested_credentials_json = json!({ + "self_attested_attributes": json!({}), + "requested_attributes": json!({ + "attr1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp, "revealed":true }) + }), + "requested_predicates": json!({ + "predicate1_referent": json!({ "cred_id": credential.referent, "timestamp":timestamp }) + }) + }).to_string(); + + let schemas_json = json!({ + schema_id: serde_json::from_str::(&schema_json).unwrap() + }).to_string(); + + let credential_defs_json = json!({ + cred_def_id: serde_json::from_str::(&cred_def_json).unwrap() + }).to_string(); + + let rev_states_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_state_json).unwrap() + }) + }).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_request, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &credential_defs_json, + &rev_states_json).unwrap(); + + //9. Verifier verifies proof before it will be revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&rev_reg_entry_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + //10. Issuer revokes credential + let revoc_reg_delta_json = anoncreds::issuer_revoke_credential(issuer_wallet_handle, + blob_storage_reader_handle, + &rev_reg_id, + &cred_rev_id).unwrap(); + + //11. Verifier verifies proof after that was revoked + let rev_reg_defs_json = json!({ + rev_reg_id.clone(): serde_json::from_str::(&revoc_reg_def_json).unwrap() + }).to_string(); + + let rev_regs_json = json!({ + rev_reg_id.clone(): json!({ + timestamp.to_string(): serde_json::from_str::(&revoc_reg_delta_json).unwrap() + }) + }).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_request, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(!valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_full_revocation_registry() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Prover creates wallet, gets wallet handle + let prover_2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //4. Prover creates wallet, gets wallet handle + let prover_3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //5 Issuer creates Schema, Credential Definition and Revocation Registry + let (_, _, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + //6. Prover1 creates Master Secret + let prover_1_master_secret = "prover1_master_secret"; + anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret).unwrap(); + + + anoncreds::multi_steps_create_revocation_credential(prover_1_master_secret, + prover_1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle); + + //7. Issuance Credential for Prover2 + // Prover2 creates Master Secret + let prover_2_master_secret = "prover2_master_secret"; + anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret).unwrap(); + + anoncreds::multi_steps_create_revocation_credential(prover_2_master_secret, + prover_2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle); + + //8. Issuance Credential for Prover3 + let prover_3_master_secret = "prover_3_master_secret"; + anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret).unwrap(); + + let cred_offer_json = anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + let (cred_req_json, _) = anoncreds::prover_create_credential_req(prover_3_wallet_handle, + DID_MY2, + &cred_offer_json, + &cred_def_json, + prover_3_master_secret).unwrap(); + + let res = anoncreds::issuer_create_credential(issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + Some(&rev_reg_id), + Some(blob_storage_reader_handle)); + assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_1_wallet_handle).unwrap(); + wallet::close_wallet(prover_2_wallet_handle).unwrap(); + wallet::close_wallet(prover_3_wallet_handle).unwrap(); + + utils::tear_down(); + } + + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_full_revocation_registry() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Prover creates wallet, gets wallet handle + let prover_1_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Prover creates wallet, gets wallet handle + let prover_2_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //4. Prover creates wallet, gets wallet handle + let prover_3_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //5 Issuer creates Schema, Credential Definition and Revocation Registry + let (_, _, + cred_def_id, cred_def_json, + rev_reg_id, revoc_reg_def_json, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_BY_DEFAULT"}"#); + + // Prover1 creates Master Secret + let prover_1_master_secret = "prover1_master_secret"; + anoncreds::prover_create_master_secret(prover_1_wallet_handle, prover_1_master_secret).unwrap(); + + anoncreds::multi_steps_create_revocation_credential(prover_1_master_secret, + prover_1_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + &anoncreds::gvt_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle); + + //9. Issuance Credential for Prover2 + // Prover2 creates Master Secret + let prover_2_master_secret = "prover2_master_secret"; + anoncreds::prover_create_master_secret(prover_2_wallet_handle, prover_2_master_secret).unwrap(); + + anoncreds::multi_steps_create_revocation_credential(prover_2_master_secret, + prover_2_wallet_handle, + issuer_wallet_handle, + CREDENTIAL2_ID, + &anoncreds::gvt2_credential_values_json(), + &cred_def_id, + &cred_def_json, + &rev_reg_id, + &revoc_reg_def_json, + blob_storage_reader_handle); + + //10. Issuance Credential for Prover3 + let prover_3_master_secret = "prover_3_master_secret"; + anoncreds::prover_create_master_secret(prover_3_wallet_handle, prover_3_master_secret).unwrap(); + + let cred_offer_json = anoncreds::issuer_create_credential_offer(issuer_wallet_handle, &cred_def_id).unwrap(); + + let (cred_req_json, _) = anoncreds::prover_create_credential_req(prover_3_wallet_handle, + DID_MY2, + &cred_offer_json, + &cred_def_json, + prover_3_master_secret).unwrap(); + + let res = anoncreds::issuer_create_credential(issuer_wallet_handle, + &cred_offer_json, + &cred_req_json, + &anoncreds::gvt_credential_values_json(), + Some(&rev_reg_id), + Some(blob_storage_reader_handle)); + assert_code!(ErrorCode::AnoncredsRevocationRegistryFullError, res); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_1_wallet_handle).unwrap(); + wallet::close_wallet(prover_2_wallet_handle).unwrap(); + wallet::close_wallet(prover_3_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_demand_revocation_strategy_for_revoke_not_issued_credential_id() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Issuer creates schema + let (_, schema_json) = anoncreds::issuer_create_schema(ISSUER_DID, + GVT_SCHEMA_NAME, + SCHEMA_VERSION, + GVT_SCHEMA_ATTRIBUTES).unwrap(); + + //3. Issuer creates credential definition + let (cred_def_id, _) = anoncreds::issuer_create_credential_definition(issuer_wallet_handle, + ISSUER_DID, + &schema_json, + TAG_1, + None, + Some(&anoncreds::revocation_cred_def_config())).unwrap(); + + //4. Issuer creates revocation registry for 2 Credentials + let tails_writer_config = anoncreds::tails_writer_config(); + let tails_writer_handle = utils::blob_storage::open_writer("default", &tails_writer_config).unwrap(); + + let (rev_reg_id, _, _) = + anoncreds::issuer_create_and_store_revoc_reg(issuer_wallet_handle, + &ISSUER_DID, + None, + TAG_1, + &cred_def_id, + r#"{"max_cred_num":2, "issuance_type":"ISSUANCE_ON_DEMAND"}"#, + tails_writer_handle).unwrap(); + + let blob_storage_reader_handle = utils::blob_storage::open_reader(TYPE, &tails_writer_config).unwrap(); + + //5. Issuer revokes Credential by not issued id + let cred_rev_id = "100"; + let res = anoncreds::issuer_revoke_credential(issuer_wallet_handle, blob_storage_reader_handle, &rev_reg_id, cred_rev_id); + assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + + utils::tear_down(); + } + + #[cfg(feature = "revocation_tests")] + #[test] + fn anoncreds_works_for_issuance_by_default_revocation_strategy_for_revoke_not_issued_credential_id() { + utils::setup(); + + //1. Issuer creates wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2 Issuer creates Schema, Credential Definition and Revocation Registry + let (_, _, + _, _, + rev_reg_id, _, _, + blob_storage_reader_handle) = anoncreds::multi_steps_issuer_revocation_preparation(issuer_wallet_handle, + ISSUER_DID, + GVT_SCHEMA_NAME, + GVT_SCHEMA_ATTRIBUTES, + r#"{"max_cred_num":5, "issuance_type":"ISSUANCE_ON_DEMAND"}"#); + + //3. Issuer revokes Credential by not issued id + let cred_rev_id = 10.to_string(); + let res = anoncreds::issuer_revoke_credential(issuer_wallet_handle, blob_storage_reader_handle, &rev_reg_id, &cred_rev_id); + assert_code!(ErrorCode::AnoncredsInvalidUserRevocId, res); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + + utils::tear_down(); + } + + + #[test] + fn anoncreds_works_for_multiple_requested_predicates_from_one_credential() { + utils::setup(); + + //1. Create Issuer wallet, gets wallet handle + let issuer_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //2. Create Prover wallet, gets wallet handle + let prover_wallet_handle = wallet::create_and_open_default_wallet().unwrap(); + + //3. Issuer creates Schema and Credential Definition + let attr_names = r#"["task1", + "task2", + "task3", + "task4", + "task5", + "6*_task", + "7*_task", + "bonus", + "average", + "aggregated", + "total"]"#; + let (schema_id, schema_json, cred_def_id, cred_def_json) = + anoncreds::multi_steps_issuer_preparation(issuer_wallet_handle, + ISSUER_DID, + "test", + attr_names); + + //4. Prover creates Master Secret + anoncreds::prover_create_master_secret(prover_wallet_handle, COMMON_MASTER_SECRET).unwrap(); + + //5. Issuance credential for Prover + let cred_values = r#"{ + "task1": {"raw":"8", "encoded": "8"}, + "task2": {"raw":"8", "encoded": "8"}, + "task3": {"raw":"10", "encoded": "10"}, + "task4": {"raw":"9", "encoded": "9"}, + "task5": {"raw":"7", "encoded": "7"}, + "6*_task": {"raw":"8", "encoded": "8"}, + "7*_task": {"raw":"9", "encoded": "9"}, + "bonus": {"raw":"5", "encoded": "5"}, + "average": {"raw":"9", "encoded": "9"}, + "aggregated": {"raw":"9", "encoded": "9"}, + "total": {"raw":"77", "encoded": "77"} + }"#; + + anoncreds::multi_steps_create_credential(COMMON_MASTER_SECRET, + prover_wallet_handle, + issuer_wallet_handle, + CREDENTIAL1_ID, + cred_values, + &cred_def_id, + &cred_def_json); + + //6. Proof request + let proof_req_json = r#"{ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes":{}, + "requested_predicates":{ + "predicate1_referent":{"name":"task1","p_type":">=","p_value":5}, + "predicate2_referent":{"name":"task2","p_type":">=","p_value":7}, + "predicate3_referent":{"name":"task3","p_type":">=","p_value":7}, + "predicate4_referent":{"name":"task4","p_type":">=","p_value":8}, + "predicate5_referent":{"name":"task5","p_type":">=","p_value":5}, + "predicate6_referent":{"name":"6*_task","p_type":">=","p_value":7}, + "predicate7_referent":{"name":"7*_task","p_type":">=","p_value":7}, + "predicate8_referent":{"name":"bonus","p_type":">=","p_value":3}, + "predicate9_referent":{"name":"average","p_type":">=","p_value":8}, + "predicate10_referent":{"name":"aggregated","p_type":">=","p_value":7}, + "predicate11_referent":{"name":"total","p_type":">=","p_value":70} + } + }"#; + + //7. Prover gets Credentials for Proof Request + let credentials_json = anoncreds::prover_get_credentials_for_proof_req(prover_wallet_handle, &proof_req_json).unwrap(); + let credential = anoncreds::get_credential_for_predicate_referent(&credentials_json, "predicate1_referent"); + + //8. Prover creates Proof + let requested_credentials_json = format!(r#"{{ + "self_attested_attributes":{{}}, + "requested_attributes":{{}}, + "requested_predicates":{{ + "predicate1_referent":{{ "cred_id":"{}" }}, + "predicate2_referent":{{ "cred_id":"{}" }}, + "predicate3_referent":{{ "cred_id":"{}" }}, + "predicate4_referent":{{ "cred_id":"{}" }}, + "predicate5_referent":{{ "cred_id":"{}" }}, + "predicate6_referent":{{ "cred_id":"{}" }}, + "predicate7_referent":{{ "cred_id":"{}" }}, + "predicate8_referent":{{ "cred_id":"{}" }}, + "predicate9_referent":{{ "cred_id":"{}" }}, + "predicate10_referent":{{ "cred_id":"{}" }}, + "predicate11_referent":{{ "cred_id":"{}" }} + }} + }}"#, credential.referent, credential.referent, credential.referent, credential.referent, credential.referent, + credential.referent, credential.referent, credential.referent, credential.referent, credential.referent, credential.referent); + + let schemas_json = json!({schema_id: serde_json::from_str::(&schema_json).unwrap()}).to_string(); + let cred_defs_json = json!({cred_def_id: serde_json::from_str::(&cred_def_json).unwrap()}).to_string(); + let rev_states_json = json!({}).to_string(); + + let proof_json = anoncreds::prover_create_proof(prover_wallet_handle, + &proof_req_json, + &requested_credentials_json, + COMMON_MASTER_SECRET, + &schemas_json, + &cred_defs_json, + &rev_states_json).unwrap(); + + let _proof: Proof = serde_json::from_str(&proof_json).unwrap(); + + //9. Verifier verifies proof + let rev_reg_defs_json = json!({}).to_string(); + let rev_regs_json = json!({}).to_string(); + + let valid = anoncreds::verifier_verify_proof(&proof_req_json, + &proof_json, + &schemas_json, + &cred_defs_json, + &rev_reg_defs_json, + &rev_regs_json).unwrap(); + assert!(valid); + + wallet::close_wallet(issuer_wallet_handle).unwrap(); + wallet::close_wallet(prover_wallet_handle).unwrap(); + + utils::tear_down(); + } +} diff --git a/libindy/tests/demo.rs b/libindy/tests/demo.rs index 0a722a710c..88071f6363 100644 --- a/libindy/tests/demo.rs +++ b/libindy/tests/demo.rs @@ -455,7 +455,7 @@ fn anoncreds_demo_works() { assert_eq!(ErrorCode::Success, ErrorCode::from(err)); let (err, valid) = verifier_verify_proof_receiver.recv_timeout(timeout::long_timeout()).unwrap(); assert_eq!(ErrorCode::Success, ErrorCode::from(err)); - assert_eq!(valid, true as u8); // TODO: FIXME + assert!(valid); // Issuer Closes Wallet let res = unsafe { @@ -837,7 +837,7 @@ fn crypto_demo_works() { assert_eq!(ErrorCode::Success, ErrorCode::from(err)); let (err, valid) = verify_receiver.recv_timeout(timeout::long_timeout()).unwrap(); - assert_eq!(valid, true as u8); + assert!(valid); assert_eq!(ErrorCode::Success, ErrorCode::from(err)); // 6. Close Wallet diff --git a/libindy/tests/ledger.rs b/libindy/tests/ledger.rs index 657924d40b..07283d2576 100644 --- a/libindy/tests/ledger.rs +++ b/libindy/tests/ledger.rs @@ -1675,7 +1675,7 @@ mod high_cases { const ADD_AUTH_ACTION: &str = "ADD"; const EDIT_AUTH_ACTION: &str = "EDIT"; const FIELD: &str = "role"; - const OLD_VALUE: &str = "0"; + const VALUE: &str = "0"; const NEW_VALUE: &str = "101"; const ROLE_CONSTRAINT: &str = r#"{ "sig_count": 1, @@ -1686,13 +1686,59 @@ mod high_cases { }"#; #[test] - fn indy_build_auth_rule_request_works_for_add_action() { + fn indy_build_auth_rule_requests_works_for_adding_new_trustee() { + // write let expected_result = json!({ "type": constants::AUTH_RULE, "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, "field": FIELD, - "new_value": NEW_VALUE, + "new_value": VALUE, + "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, + Some(VALUE), + ROLE_CONSTRAINT).unwrap(); + check_request(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": VALUE, + }); + + let request = ledger::build_get_auth_rule_request(None, + Some(constants::NYM), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + Some(VALUE)).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_adding_new_identity_owner() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, "constraint": json!({ "sig_count": 1, "metadata": {}, @@ -1707,20 +1753,85 @@ mod high_cases { &ADD_AUTH_ACTION, FIELD, None, - NEW_VALUE, + None, ROLE_CONSTRAINT).unwrap(); check_request(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": ADD_AUTH_ACTION, + "field": FIELD, + "new_value": serde_json::Value::Null, + }); + + let request = ledger::build_get_auth_rule_request(None, + Some(constants::NYM), + Some(ADD_AUTH_ACTION), + Some(FIELD), + None, + None).unwrap(); + check_request(&request, expected_result); } #[test] - fn indy_build_auth_rule_request_works_for_edit_action() { + fn indy_build_auth_rule_requests_works_for_demote_trustee() { + // write let expected_result = json!({ "type": constants::AUTH_RULE, "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, "field": FIELD, - "old_value": OLD_VALUE, - "new_value": NEW_VALUE, + "old_value": VALUE, + "new_value": serde_json::Value::Null, + "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(VALUE), + None, + ROLE_CONSTRAINT).unwrap(); + check_request(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": VALUE, + "new_value": serde_json::Value::Null, + }); + + let request = ledger::build_get_auth_rule_request(None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + Some(VALUE), + None).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_promote_role_to_trustee() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": serde_json::Value::Null, + "new_value": VALUE, "constraint": json!({ "sig_count": 1, "metadata": {}, @@ -1734,10 +1845,75 @@ mod high_cases { constants::NYM, &EDIT_AUTH_ACTION, FIELD, - Some(OLD_VALUE), - NEW_VALUE, + None, + Some(VALUE), ROLE_CONSTRAINT).unwrap(); check_request(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": serde_json::Value::Null, + "new_value": VALUE, + }); + + let request = ledger::build_get_auth_rule_request(None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + None, + Some(VALUE)).unwrap(); + check_request(&request, expected_result); + } + + #[test] + fn indy_build_auth_rule_requests_works_for_change_trustee_to_steward() { + // write + let expected_result = json!({ + "type": constants::AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": "0", + "new_value": "2", + "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("0"), + Some("2"), + ROLE_CONSTRAINT).unwrap(); + check_request(&request, expected_result); + + // read + let expected_result = json!({ + "type": constants::GET_AUTH_RULE, + "auth_type": constants::NYM, + "auth_action": EDIT_AUTH_ACTION, + "field": FIELD, + "old_value": "0", + "new_value": "2", + }); + + let request = ledger::build_get_auth_rule_request(None, + Some(constants::NYM), + Some(EDIT_AUTH_ACTION), + Some(FIELD), + Some("0"), + Some("2")).unwrap(); + check_request(&request, expected_result); } #[test] @@ -1786,7 +1962,7 @@ mod high_cases { &ADD_AUTH_ACTION, FIELD, None, - NEW_VALUE, + Some(NEW_VALUE), constraint).unwrap(); check_request(&request, expected_result); } @@ -1798,33 +1974,13 @@ mod high_cases { &ADD_AUTH_ACTION, FIELD, None, - NEW_VALUE, + Some(NEW_VALUE), r#"{"field":"value"}"#); assert_code!(ErrorCode::CommonInvalidStructure, res); } #[test] - fn indy_build_get_auth_rule_request_works_for_all_fields() { - let expected_result = json!({ - "type": constants::GET_AUTH_RULE, - "auth_type": constants::NYM, - "field": FIELD, - "old_value": OLD_VALUE, - "new_value": NEW_VALUE, - "auth_action": ADD_AUTH_ACTION, - }); - - let request = ledger::build_get_auth_rule_request(Some(DID_TRUSTEE), - Some(constants::NYM), - Some(ADD_AUTH_ACTION), - Some(FIELD), - Some(OLD_VALUE), - Some(NEW_VALUE)).unwrap(); - check_request(&request, expected_result); - } - - #[test] - fn indy_build_get_auth_rule_request_works_for_all_fields_are_skipped() { + fn indy_build_get_auth_rule_request_works_for_get_all() { let expected_result = json!({ "type": constants::GET_AUTH_RULE, }); @@ -1851,24 +2007,151 @@ mod high_cases { #[test] #[cfg(feature = "local_nodes_pool")] - fn indy_auth_rule_requests_work() { + fn indy_auth_rule_requests_works_for_adding_new_trustee() { + let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); + + let (_, default_constraint_json) = _get_constraint(pool_handle, ADD_AUTH_ACTION, + constants::NYM, FIELD, + None, Some(VALUE)); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, ADD_AUTH_ACTION, + constants::NYM, FIELD, + None, Some(VALUE), ROLE_CONSTRAINT); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint(pool_handle, ADD_AUTH_ACTION, + constants::NYM, FIELD, + None, Some(VALUE)); + + let expected_constraint: serde_json::Value = serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, ADD_AUTH_ACTION, + constants::NYM, FIELD, + None, Some(VALUE), &default_constraint_json); + + utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_adding_new_identity_owner() { + let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); + + let (_, default_constraint_json) = _get_constraint(pool_handle, + &ADD_AUTH_ACTION, + constants::NYM, + FIELD, + None, + None); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, ADD_AUTH_ACTION, + constants::NYM, FIELD, None, None, ROLE_CONSTRAINT); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint(pool_handle, ADD_AUTH_ACTION, + constants::NYM, FIELD, None, None); + + let expected_constraint: serde_json::Value = serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, ADD_AUTH_ACTION, constants::NYM, + FIELD, None, None, &default_constraint_json); + + utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_demote_trustee() { + let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); + + let (_, default_constraint_json) = _get_constraint(pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some(VALUE), + None); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, + constants::NYM, FIELD, Some(VALUE), None, ROLE_CONSTRAINT); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint(pool_handle, EDIT_AUTH_ACTION, constants::NYM, + FIELD, Some(VALUE), None); + + let expected_constraint: serde_json::Value = serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, constants::NYM, + FIELD, Some(VALUE), None, &default_constraint_json); + + utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_promote_role_to_trustee() { let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); - let constraint_id = _build_constraint_id(ADD_AUTH_ACTION, constants::NYM, FIELD, None, NEW_VALUE); + let (_, default_constraint_json) = _get_constraint(pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + None, + Some(VALUE)); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, + constants::NYM, FIELD, None, Some(VALUE), ROLE_CONSTRAINT); + + ::std::thread::sleep(::std::time::Duration::from_secs(1)); + + let (actual_constraint, _) = _get_constraint(pool_handle, EDIT_AUTH_ACTION, constants::NYM, + FIELD, None, Some(VALUE)); + + let expected_constraint: serde_json::Value = serde_json::from_str(ROLE_CONSTRAINT).unwrap(); + + assert_eq!(expected_constraint, actual_constraint); + + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, constants::NYM, + FIELD, None, Some(VALUE), &default_constraint_json); + + utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); + } + + #[test] + #[cfg(feature = "local_nodes_pool")] + fn indy_auth_rule_requests_works_for_change_trustee_to_steward() { + let (wallet_handle, pool_handle, trustee_did) = utils::setup_trustee(); - let default_constraint = _get_constraint(pool_handle, &constraint_id); + let (_, default_constraint_json) = _get_constraint(pool_handle, + &EDIT_AUTH_ACTION, + constants::NYM, + FIELD, + Some("0"), + Some("2")); - _change_constraint(pool_handle, wallet_handle, &trustee_did, ROLE_CONSTRAINT); + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, + constants::NYM, FIELD, Some("0"), + Some("2"), ROLE_CONSTRAINT); ::std::thread::sleep(::std::time::Duration::from_secs(1)); - let actual_constraint = _get_constraint(pool_handle, &constraint_id); + let (actual_constraint, _) = _get_constraint(pool_handle, EDIT_AUTH_ACTION, + constants::NYM, FIELD, Some("0"), Some("2")); let expected_constraint: serde_json::Value = serde_json::from_str(ROLE_CONSTRAINT).unwrap(); assert_eq!(expected_constraint, actual_constraint); - _change_constraint(pool_handle, wallet_handle, &trustee_did, &serde_json::to_string(&default_constraint).unwrap()); + _change_constraint(pool_handle, wallet_handle, &trustee_did, EDIT_AUTH_ACTION, + constants::NYM, FIELD, Some("0"), Some("2"), &default_constraint_json); utils::tear_down_with_wallet_and_pool(wallet_handle, pool_handle); } @@ -1877,32 +2160,38 @@ mod high_cases { auth_type: &str, field: &str, old_value: Option<&str>, - new_value: &str) -> String { - format!("{}--{}--{}--{}--{}", auth_action, auth_type, field, old_value.unwrap_or("*"), new_value) + new_value: Option<&str>) -> String { + let default_old_value = if auth_action == "ADD" { "*" } else { "" }; + format!("{}--{}--{}--{}--{}", auth_type, auth_action, field, old_value.unwrap_or(default_old_value), new_value.unwrap_or("")) } - fn _change_constraint(pool_handle: i32, wallet_handle: i32, trustee_did: &str, constraint: &str) { + fn _change_constraint(pool_handle: i32, wallet_handle: i32, trustee_did: &str, action: &str, txn_type: &str, field: &str, + old_value: Option<&str>, new_value: Option<&str>, constraint: &str) { let auth_rule_request = ledger::build_auth_rule_request(&trustee_did, - constants::NYM, - &ADD_AUTH_ACTION, - FIELD, - None, - NEW_VALUE, + txn_type, + &action, + field, + old_value, + new_value, 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); } - fn _get_constraint(pool_handle: i32, constraint_id: &str) -> serde_json::Value { + fn _get_constraint(pool_handle: i32, action: &str, txn_type: &str, field: &str, + old_value: Option<&str>, new_value: Option<&str>) -> (serde_json::Value, String) { let get_auth_rule_request = ledger::build_get_auth_rule_request(None, - Some(constants::NYM), - Some(ADD_AUTH_ACTION), - Some(FIELD), - None, - Some(NEW_VALUE)).unwrap(); + Some(txn_type), + Some(action), + Some(field), + old_value, + new_value).unwrap(); let response = ledger::submit_request(pool_handle, &get_auth_rule_request).unwrap(); + let constraint_id = _build_constraint_id(action, txn_type, field, old_value, new_value); - _extract_constraint(&response, constraint_id) + let constraint = _extract_constraint(&response, &constraint_id); + let constraint_json = serde_json::to_string(&constraint).unwrap(); + (constraint, constraint_json) } fn _extract_constraint(response: &str, constraint_id: &str) -> serde_json::Value { @@ -2382,7 +2671,8 @@ mod medium_cases { fn indy_send_node_request_works_for_wrong_role() { let (wallet_handle, pool_handle, did) = utils::setup_trustee(); - let node_request = ledger::build_node_request(&did, &did, NODE_DATA).unwrap(); + let key = utils::crypto::create_key(wallet_handle, None).unwrap(); + let node_request = ledger::build_node_request(&did, &key, NODE_DATA).unwrap(); let response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &did, &node_request).unwrap(); pool::check_response_type(&response, ResponseType::REJECT); @@ -2394,7 +2684,8 @@ mod medium_cases { fn indy_submit_node_request_works_for_steward_already_has_node() { let (wallet_handle, pool_handle, did) = utils::setup_steward(); - let node_request = ledger::build_node_request(&did, &did, NODE_DATA).unwrap(); + let key = utils::crypto::create_key(wallet_handle, None).unwrap(); + let node_request = ledger::build_node_request(&did, &key, NODE_DATA).unwrap(); let response = ledger::sign_and_submit_request(pool_handle, wallet_handle, &did, &node_request).unwrap(); pool::check_response_type(&response, ResponseType::REJECT); diff --git a/libindy/tests/utils/callback.rs b/libindy/tests/utils/callback.rs index cc473ea885..883948ac16 100644 --- a/libindy/tests/utils/callback.rs +++ b/libindy/tests/utils/callback.rs @@ -93,23 +93,23 @@ pub fn _closure_to_cb_ec_i32_usize() -> (Receiver<(ErrorCode, i32, usize)>, i32, (receiver, command_handle, Some(_callback)) } -pub fn _closure_to_cb_ec_bool() -> (Receiver<(ErrorCode, u8)>, i32, +pub fn _closure_to_cb_ec_bool() -> (Receiver<(ErrorCode, bool)>, i32, Option) { + valid: bool)>) { let (sender, receiver) = channel(); lazy_static! { - static ref CALLBACKS: Mutex>> = Default::default(); + static ref CALLBACKS: Mutex>> = Default::default(); } let closure = Box::new(move |err, val| { sender.send((err, val)).unwrap(); }); - extern "C" fn _callback(command_handle: i32, err: ErrorCode, valid: u8) { + extern "C" fn _callback(command_handle: i32, err: ErrorCode, valid: bool) { let mut callbacks = CALLBACKS.lock().unwrap(); let mut cb = callbacks.remove(&command_handle).unwrap(); - cb(err, valid as u8) + cb(err, valid) } let mut callbacks = CALLBACKS.lock().unwrap(); diff --git a/libindy/tests/utils/ledger.rs b/libindy/tests/utils/ledger.rs index 43b36ef395..427fc06708 100644 --- a/libindy/tests/utils/ledger.rs +++ b/libindy/tests/utils/ledger.rs @@ -205,7 +205,7 @@ pub fn build_auth_rule_request(submitter_did: &str, action: &str, field: &str, old_value: Option<&str>, - new_value: &str, + new_value: Option<&str>, constraint: &str, ) -> Result { ledger::build_auth_rule_request(submitter_did, txn_type, action, field, old_value, new_value, constraint).wait() } diff --git a/libnullpay/Cargo.lock b/libnullpay/Cargo.lock index 696fd857f8..020e398c09 100644 --- a/libnullpay/Cargo.lock +++ b/libnullpay/Cargo.lock @@ -169,11 +169,11 @@ dependencies = [ [[package]] name = "indy" -version = "1.8.2" +version = "1.8.3" dependencies = [ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "indy-sys 1.8.2", + "indy-sys 1.8.3", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -186,7 +186,7 @@ dependencies = [ [[package]] name = "indy-sys" -version = "1.8.2" +version = "1.8.3" dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -247,12 +247,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "null-payment-method" -version = "1.8.2" +version = "1.8.3" dependencies = [ "android_logger 0.5.3 (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)", - "indy 1.8.2", + "indy 1.8.3", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/libnullpay/Cargo.toml b/libnullpay/Cargo.toml index 1e6936654f..9dffdc34d9 100644 --- a/libnullpay/Cargo.toml +++ b/libnullpay/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "null-payment-method" -version = "1.8.2" +version = "1.8.3" authors = ["Nikita Khateev "] build = "build.rs" @@ -25,7 +25,7 @@ serde_derive = "1.0" [dev-dependencies] dirs = "1.0.4" -indy = { version="1.8.2", path="../wrappers/rust" } +indy = { version="1.8.3", path="../wrappers/rust" } [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" \ No newline at end of file diff --git a/libnullpay/debian/changelog b/libnullpay/debian/changelog index 29cb38f421..0ab44e2346 100644 --- a/libnullpay/debian/changelog +++ b/libnullpay/debian/changelog @@ -1,4 +1,4 @@ -libnullpay (1.8.2) unstable; urgency=medium +libnullpay (1.8.3) unstable; urgency=medium [ Hyperledger ] * Initial release diff --git a/vcx/docs/migration-guide-0.1.x-0.2.0.md b/vcx/docs/migration-guide-0.1.x-0.2.0.md index bdcf64c400..cc718bc595 100644 --- a/vcx/docs/migration-guide-0.1.x-0.2.0.md +++ b/vcx/docs/migration-guide-0.1.x-0.2.0.md @@ -475,4 +475,8 @@ Added `protocol_type` field to VCX provisioning config with indicates A2A messag
vcx_get_current_error(error_json_p: *mut *const c_char)
- \ No newline at end of file + + +## Libvcx 0.2.2 to 0.2.3 migration Guide + +The Libvcx 0.2.3 release contains fixes that don't affect API functions. \ No newline at end of file diff --git a/vcx/dummy-cloud-agent/Cargo.lock b/vcx/dummy-cloud-agent/Cargo.lock index b9dbf0ed31..8ec86c1f43 100644 --- a/vcx/dummy-cloud-agent/Cargo.lock +++ b/vcx/dummy-cloud-agent/Cargo.lock @@ -582,11 +582,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "indy" -version = "1.8.1" +version = "1.8.2" dependencies = [ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "indy-sys 1.8.1", + "indy-sys 1.8.2", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -609,7 +609,7 @@ dependencies = [ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", - "indy 1.8.1", + "indy 1.8.2", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "indy-sys" -version = "1.8.1" +version = "1.8.2" dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/vcx/dummy-cloud-agent/Cargo.toml b/vcx/dummy-cloud-agent/Cargo.toml index f6ab5610d2..2052124db3 100644 --- a/vcx/dummy-cloud-agent/Cargo.toml +++ b/vcx/dummy-cloud-agent/Cargo.toml @@ -2,6 +2,7 @@ name = "indy-dummy-agent" version = "0.1.0" authors = ["Vyacheslav Gudkov "] +exclude = ['config/*'] [dependencies] actix = "0.7" diff --git a/vcx/dummy-cloud-agent/sample-config.json b/vcx/dummy-cloud-agent/config/sample-config.json similarity index 100% rename from vcx/dummy-cloud-agent/sample-config.json rename to vcx/dummy-cloud-agent/config/sample-config.json diff --git a/vcx/dummy-cloud-agent/src/actors/agent.rs b/vcx/dummy-cloud-agent/src/actors/agent.rs index 484ca51287..100e0b3975 100644 --- a/vcx/dummy-cloud-agent/src/actors/agent.rs +++ b/vcx/dummy-cloud-agent/src/actors/agent.rs @@ -36,7 +36,7 @@ impl Agent { trace!("Agent::create >> {:?}, {:?}, {:?}, {:?}", owner_did, owner_verkey, forward_agent_detail, wallet_storage_config); - let wallet_id = rand::rand_string(10); + let wallet_id = format!("dummy_{}_{}", owner_did, rand::rand_string(10)); let wallet_key = rand::rand_string(10); let wallet_config = json!({ diff --git a/vcx/libvcx/Cargo.lock b/vcx/libvcx/Cargo.lock index 369c33cd71..f25ee9bdba 100644 --- a/vcx/libvcx/Cargo.lock +++ b/vcx/libvcx/Cargo.lock @@ -461,11 +461,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "indy" -version = "1.8.2" +version = "1.8.3" dependencies = [ "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-sys 1.8.2", + "indy-sys 1.8.3", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -478,7 +478,7 @@ dependencies = [ [[package]] name = "indy-sys" -version = "1.8.2" +version = "1.8.3" dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -555,7 +555,7 @@ dependencies = [ [[package]] name = "libvcx" -version = "0.2.3" +version = "0.2.4" dependencies = [ "android_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -564,8 +564,8 @@ dependencies = [ "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.2", - "indy-sys 1.8.2", + "indy 1.8.3", + "indy-sys 1.8.3", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/vcx/libvcx/Cargo.toml b/vcx/libvcx/Cargo.toml index 1e5386c148..8680b47346 100644 --- a/vcx/libvcx/Cargo.toml +++ b/vcx/libvcx/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libvcx" -version = "0.2.3" +version = "0.2.4" authors = [ "Evernym Inc." ] publish = false description = "This is the official SDK for Evernym's VCX" @@ -46,8 +46,8 @@ rmp-serde = "0.13.7" base64 = "0.8.0" openssl = "0.10" num-traits = "0.2.0" -indy = { version = "1.8.2", path = "../../wrappers/rust/" } -indy-sys = { version = "1.8.2", path = "../../wrappers/rust/indy-sys/" } +indy = { version = "1.8.3", path = "../../wrappers/rust/" } +indy-sys = { version = "1.8.3", path = "../../wrappers/rust/indy-sys/" } log-panics = "2.0.0" tokio-threadpool = "0.1.6" futures = "0.1.23" diff --git a/vcx/libvcx/debian/changelog b/vcx/libvcx/debian/changelog index c07cff0c51..0fb90aee82 100644 --- a/vcx/libvcx/debian/changelog +++ b/vcx/libvcx/debian/changelog @@ -1,7 +1,10 @@ -libvcx (0.2.3) unstable; urgency=medium +libvcx (0.2.4) unstable; urgency=medium [ Hyperledger ] +* 0.2.4 + * Bugfixes + * 0.2.3 * Updated Vcx to support community A2A protocol. Added `protocol_type` field to VCX provisioning config with indicates A2A message format will be used. diff --git a/vcx/libvcx/include/vcx.h b/vcx/libvcx/include/vcx.h index 889427048f..4da11eefd7 100644 --- a/vcx/libvcx/include/vcx.h +++ b/vcx/libvcx/include/vcx.h @@ -1,6 +1,8 @@ #ifndef __VCX_H #define __VCX_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -16,7 +18,7 @@ typedef unsigned int vcx_proof_handle_t; typedef unsigned int vcx_command_handle_t; typedef unsigned int vcx_payment_handle_t; typedef unsigned int vcx_wallet_search_handle_t; -typedef unsigned int vcx_bool_t; +typedef unsigned bool vcx_bool_t; typedef unsigned int count_t; typedef unsigned long vcx_price_t; typedef unsigned int vcx_u32_t; diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index 74b0de2d4b..f59d44af1c 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -245,10 +245,10 @@ impl Credential { } let credential_offer = self.credential_offer.as_ref().ok_or(VcxError::from(VcxErrorKind::InvalidState))?; - let credential_offer_json = serde_json::to_string(credential_offer) + let credential_offer_json = serde_json::to_value(credential_offer) .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidCredential, format!("Cannot deserialize CredentilOffer: {}", err)))?; - Ok(self.to_cred_offer_string(&credential_offer_json)) + Ok(self.to_cred_offer_string(credential_offer_json)) } fn get_credential_id(&self) -> String { @@ -270,9 +270,9 @@ impl Credential { serde_json::Value::from(json).to_string() } - fn to_cred_offer_string(&self, cred_offer: &str) -> String { + fn to_cred_offer_string(&self, cred_offer: Value) -> String { let mut json = serde_json::Map::new(); - json.insert("credential_offer".to_string(), Value::String(cred_offer.to_string())); + json.insert("credential_offer".to_string(), cred_offer); self.set_payment_info(&mut json); serde_json::Value::from(json).to_string() } @@ -726,4 +726,15 @@ pub mod tests { let new_balance = get_wallet_token_info().unwrap().get_balance(); assert_eq!(new_balance, balance); } + + #[test] + fn test_get_cred_offer_returns_json_string_with_cred_offer_json_nested() { + init!("true"); + let handle = from_string(::utils::constants::DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); + let offer_string = get_credential_offer(handle).unwrap(); + let offer_value: serde_json::Value = serde_json::from_str(&offer_string).unwrap(); + + let offer_struct: CredentialOffer = serde_json::from_value(offer_value["credential_offer"].clone()).unwrap(); + + } } diff --git a/vcx/wrappers/java/build.gradle b/vcx/wrappers/java/build.gradle index f8291d4f30..6e83e61d84 100755 --- a/vcx/wrappers/java/build.gradle +++ b/vcx/wrappers/java/build.gradle @@ -25,7 +25,7 @@ test { } static def versionMajor() { - return '0.2.3' + return '0.2.4' } static def version() { diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxJava.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxJava.java index 9303485d7b..e151e7e8d2 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxJava.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/VcxJava.java @@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; /** * Common functionality for the APIs, JSON parameters, and results used diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/connection/ConnectionApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/connection/ConnectionApi.java index a904d1a8c7..9d4899e7fb 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/connection/ConnectionApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/connection/ConnectionApi.java @@ -14,7 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; /** * Created by abdussami on 03/06/18. diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java index 16af06bd1b..04b441118c 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credential/CredentialApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class CredentialApi extends VcxJava.API { @@ -274,4 +274,4 @@ public static CompletableFuture credentialCreateWithOffer( return future; } -} \ No newline at end of file +} diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credentialDef/CredentialDefApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credentialDef/CredentialDefApi.java index f582495993..5b84580762 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credentialDef/CredentialDefApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/credentialDef/CredentialDefApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class CredentialDefApi extends VcxJava.API { diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/issuer/IssuerApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/issuer/IssuerApi.java index 64854cad98..ace1e75600 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/issuer/IssuerApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/issuer/IssuerApi.java @@ -8,7 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class IssuerApi extends VcxJava.API { diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/DisclosedProofApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/DisclosedProofApi.java index 4aa321f1a5..e01421d544 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/DisclosedProofApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/DisclosedProofApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class DisclosedProofApi extends VcxJava.API { diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/ProofApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/ProofApi.java index 79c7b20bc9..047df13e37 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/ProofApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/proof/ProofApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class ProofApi extends VcxJava.API { private ProofApi(){} @@ -221,4 +221,4 @@ public static Integer proofRelease( return result; } -} \ No newline at end of file +} diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/schema/SchemaApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/schema/SchemaApi.java index eedbd5d13b..9b45bb2a67 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/schema/SchemaApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/schema/SchemaApi.java @@ -10,7 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class SchemaApi extends VcxJava.API { private static final Logger logger = LoggerFactory.getLogger("SchemaApi"); diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/token/TokenApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/token/TokenApi.java index 0d3ceb2d02..5f7d27c73b 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/token/TokenApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/token/TokenApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class TokenApi extends VcxJava.API { diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/utils/UtilsApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/utils/UtilsApi.java index 91a42eaae2..73c8dde41d 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/utils/UtilsApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/utils/UtilsApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; /** diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/vcx/VcxApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/vcx/VcxApi.java index afaef8faed..ec0f630d7a 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/vcx/VcxApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/vcx/VcxApi.java @@ -10,7 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class VcxApi extends VcxJava.API { private static final Logger logger = LoggerFactory.getLogger("VcxApi"); diff --git a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/wallet/WalletApi.java b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/wallet/WalletApi.java index 37f4d7dafd..00733908a4 100644 --- a/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/wallet/WalletApi.java +++ b/vcx/wrappers/java/src/main/java/com/evernym/sdk/vcx/wallet/WalletApi.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; public class WalletApi extends VcxJava.API { private static final Logger logger = LoggerFactory.getLogger("WalletApi"); @@ -186,4 +186,4 @@ public static CompletableFuture updateRecordWallet( return future; } -} \ No newline at end of file +} diff --git a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ConnectionApiTest.java b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ConnectionApiTest.java index 14ad0294fd..35e7e0d2e1 100644 --- a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ConnectionApiTest.java +++ b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/ConnectionApiTest.java @@ -4,7 +4,7 @@ import com.evernym.sdk.vcx.connection.ConnectionApi; import com.evernym.sdk.vcx.connection.InvalidConnectionHandleException; import com.evernym.sdk.vcx.vcx.VcxApi; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.awaitility.Awaitility; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; 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 c7a28bfdd7..913a615862 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 @@ -2,7 +2,7 @@ import com.evernym.sdk.vcx.connection.ConnectionApi; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.awaitility.Awaitility; import org.junit.jupiter.api.Test; diff --git a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/TestHelper.java b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/TestHelper.java index 0a80b7d4e1..2c857986f7 100644 --- a/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/TestHelper.java +++ b/vcx/wrappers/java/src/test/java/com/evernym/sdk/vcx/TestHelper.java @@ -5,7 +5,7 @@ import com.evernym.sdk.vcx.credential.CredentialApi; import com.evernym.sdk.vcx.credentialDef.CredentialDefApi; import com.jayway.jsonpath.JsonPath; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.awaitility.Awaitility; import java.util.concurrent.ExecutionException; diff --git a/vcx/wrappers/node/package.json b/vcx/wrappers/node/package.json index 1c6f24b815..352ef4e6d0 100644 --- a/vcx/wrappers/node/package.json +++ b/vcx/wrappers/node/package.json @@ -20,7 +20,7 @@ "url": "git+https://github.com/evernym/vcx.git", "type": "git" }, - "version": "0.2.3", + "version": "0.2.4", "dependencies": { "@types/ffi": "0.0.19", "@types/node": "^8.0.47", diff --git a/vcx/wrappers/python3/setup.py b/vcx/wrappers/python3/setup.py index a27c8c571f..1664744906 100755 --- a/vcx/wrappers/python3/setup.py +++ b/vcx/wrappers/python3/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages import os -PKG_VERSION = os.environ.get('PACKAGE_VERSION') or '0.2.3' +PKG_VERSION = os.environ.get('PACKAGE_VERSION') or '0.2.4' PKG_NAME = os.environ.get('PACKAGE_NAME') or 'python3-wrapper-vcx' setup( diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Did/DidHighCases.m b/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Did/DidHighCases.m index e14a9e34e6..7dd4f5822c 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Did/DidHighCases.m +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Case Tests/Did/DidHighCases.m @@ -432,4 +432,31 @@ - (void)testAbbreviateVerkeyForAbbreviatedKey { XCTAssertFalse([verkey isEqualToString:abbrVerkey], @"Keys are equal"); } +// MARK: - List DIDs + +- (void)testListDids { + // 1. Create did1 + NSString *did1; + ret = [[DidUtils sharedInstance] createMyDidWithWalletHandle:walletHandle + myDidJson:@"{}" + outMyDid:&did1 + outMyVerkey:nil]; + XCTAssertEqual(ret.code, Success, @"DidUtils::createMyDidWithWalletHandle() failed"); + + // 2. Create did2 + NSString *did2; + ret = [[DidUtils sharedInstance] createMyDidWithWalletHandle:walletHandle + myDidJson:@"{}" + outMyDid:&did2 + outMyVerkey:nil]; + XCTAssertEqual(ret.code, Success, @"DidUtils::createMyDidWithWalletHandle() failed"); + + // 3. List DIDs in wallet + NSString *metadata; + ret = [[DidUtils sharedInstance] listMyDidsWithMeta:walletHandle metadata:&metadata]; + XCTAssertEqual(ret.code, Success, @"DidUtils::listMyDidsWithMeta() failed"); + XCTAssertTrue([metadata containsString:did1], @"Metadata does not contain first DID"); + XCTAssertTrue([metadata containsString:did2], @"Metadata does not contain second DID"); +} + @end diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.h b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.h index 7ff2deae5a..d60fc123fe 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.h +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.h @@ -86,4 +86,7 @@ - (NSError *)abbreviateVerkey:(NSString *)did fullVerkey:(NSString *)fullVerkey verkey:(NSString **)verkey; + +- (NSError *)listMyDidsWithMeta:(IndyHandle)walletHandle + metadata:(NSString **)metadata; @end diff --git a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.mm b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.mm index b3557cba1e..969dd0d36a 100644 --- a/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.mm +++ b/wrappers/ios/libindy-pod/Indy-demoTests/Test Utils/DidUtils.mm @@ -478,4 +478,22 @@ - (NSError *)abbreviateVerkey:(NSString *)did return err; } +- (NSError *)listMyDidsWithMeta:(IndyHandle)walletHandle + metadata:(NSString **)metadata { + XCTestExpectation *completionExpectation = [[XCTestExpectation alloc] initWithDescription:@"completion finished"]; + __block NSError *err = nil; + __block NSString *outMetadata; + + [IndyDid listMyDidsWithMeta:walletHandle completion:^(NSError *error, NSString *metadata) { + err = error; + outMetadata = metadata; + [completionExpectation fulfill]; + }]; + + [self waitForExpectations:@[completionExpectation] timeout:[TestUtils longTimeout]]; + + if (metadata) {*metadata = outMetadata;} + return err; +} + @end diff --git a/wrappers/ios/libindy-pod/Indy.xcodeproj/project.pbxproj b/wrappers/ios/libindy-pod/Indy.xcodeproj/project.pbxproj index 4c8c21e5d3..4b1eca533a 100644 --- a/wrappers/ios/libindy-pod/Indy.xcodeproj/project.pbxproj +++ b/wrappers/ios/libindy-pod/Indy.xcodeproj/project.pbxproj @@ -276,12 +276,12 @@ 3E08C0121EB3336A000A73BA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0830; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = Hyperledger; TargetAttributes = { 3E08C01A1EB3336A000A73BA = { CreatedOnToolsVersion = 8.3.2; - DevelopmentTeam = ES8QU3D2A4; + DevelopmentTeam = MZ3U758J7T; LastSwiftMigration = 0830; ProvisioningStyle = Automatic; }; @@ -375,15 +375,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -427,15 +435,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -471,9 +487,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ES8QU3D2A4; + DEVELOPMENT_TEAM = MZ3U758J7T; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -501,11 +518,12 @@ ); PRODUCT_BUNDLE_IDENTIFIER = org.hyperledger.indy; PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = NO; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(PROJECT_NAME)-Swift.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; USER_HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).framework/Headers $(CONTENTS_FOLDER_PATH)/Headers"; }; name = Debug; @@ -517,9 +535,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ES8QU3D2A4; + DEVELOPMENT_TEAM = MZ3U758J7T; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -547,10 +566,11 @@ ); PRODUCT_BUNDLE_IDENTIFIER = org.hyperledger.indy; PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = NO; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(PROJECT_NAME)-Swift.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; USER_HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).framework/Headers"; }; name = Release; diff --git a/wrappers/ios/libindy-pod/Indy.xcodeproj/xcshareddata/xcschemes/Indy.xcscheme b/wrappers/ios/libindy-pod/Indy.xcodeproj/xcshareddata/xcschemes/Indy.xcscheme index c13445ced1..590c1b87bc 100644 --- a/wrappers/ios/libindy-pod/Indy.xcodeproj/xcshareddata/xcschemes/Indy.xcscheme +++ b/wrappers/ios/libindy-pod/Indy.xcodeproj/xcshareddata/xcschemes/Indy.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -92,7 +90,7 @@ ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> + scriptText = "${SRCROOT}/universal_framework.sh "> type of a constraint. @@ -622,7 +622,7 @@ @param txnType - (Optional) target ledger transaction alias or associated value. @param action - (Optional) target action type. Can be either "ADD" or "EDIT". @param field - (Optional) target transaction field. - @param oldValue - (Optional) old value of field, which can be changed to a new_value (must be specified for EDIT action). + @param oldValue - (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). @param newValue - (Optional) new value that can be used to fill the field. @param completion Callback that takes command result as parameter. Returns request result as json. diff --git a/wrappers/ios/libindy-pod/Podfile b/wrappers/ios/libindy-pod/Podfile index 85eda15e56..18f262e6bf 100644 --- a/wrappers/ios/libindy-pod/Podfile +++ b/wrappers/ios/libindy-pod/Podfile @@ -8,7 +8,7 @@ def appPods pod 'libsodium' pod 'libzmq',"4.2.3" pod 'OpenSSL' - pod 'libindy', "1.6.4-739" + pod 'libindy', "1.8.2" end target 'Indy-demo' do diff --git a/wrappers/ios/libindy-pod/universal_framework.sh b/wrappers/ios/libindy-pod/universal_framework.sh index 033e11bd48..145f9d8e34 100755 --- a/wrappers/ios/libindy-pod/universal_framework.sh +++ b/wrappers/ios/libindy-pod/universal_framework.sh @@ -1,8 +1,67 @@ -#!/bin/sh +################################################################################################################################################# +# post-archive-script.sh +# +# The purpose of this script is to create a universal binary for your framework +# Also - if there is a problem with steps in this script, then it should be +# easy to debug! Other scripts that this is based off of aren't so easy to debug. +# +################################################################################################################################################# + + +# Validate that everything is setup correctly +validate() { + +# 1. Make sure the archival is coming from a workspace (not a project). +# This is because a project doesn't provide enough enviornment variables to +# correctly archive the project in the way we need to (yes, lazy programmer). +if [ "${PROJECT_NAME}" == "" ] +then +exec > /tmp/${SCHEME_NAME}_archive.log 2>&1; +echo "[ERROR]: PROJECT_NAME was not defined, did you select the 'Provide build settings from' in the 'Post-actions' for Archival?"; +envExit 1; -exec > /tmp/${PROJECT_NAME}_archive.log 2>&1 +else +exec > ${TMPDIR}/${IBSC_MODULE}_archive.log 2>&1; +fi + +# Make sure the project is setup to actually archive, otherwise we don't do anything. +if [ "${ARCHIVE_PRODUCTS_PATH}" == "" ] ; then +echo "[ERROR]: ARCHIVE_PRODUCTS_PATH is not defined - you probably need to set the SKIP_INSTALL build setting to NO" +envExit 1; +else +echo "ARCHIVE_PRODUCTS_PATH=${ARCHIVE_PRODUCTS_PATH}" +fi +} +# Configure some environment variables and ensure the universal folder exists +configure() { UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal +if [ ! -d "${UNIVERSAL_OUTPUTFOLDER}" ] +then +echo "Created a UNIVERSAL_OUTPUTHOLDER: ${UNIVERSAL_OUTPUTFOLDER}" +mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" +fi +PROJECT_FOLDER=$(dirname "${PROJECT_FILE_PATH}"); + +if [ "${CONFIGURATION}" == "" ] +then +echo "CONFIGURATION was not defined, setting it to Release" +CONFIGURATION=Release +fi +} + +# If we're going to non-zero exit, lets print out the environment first (again, +# for debugging purposes, this is very useful). +envExit() { +#env; +exit $@; +} + +# The work is done here, if we haven't been invoked yet, then go through the +# build steps, and dump the output to the log file. You'll note that there are +# no comments in this function. That's because the echo statements serve as +# those comments and provide breadcrumbs in the case that we can't build +buildFramework() { if [ "true" == ${ALREADYINVOKED:-false} ] then @@ -10,55 +69,91 @@ echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true" -# make sure the output directory exists -mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" - -if [ ${PLATFORM_NAME} = "iphonesimulator" ] +echo "Step 1. Building for iPhoneSimulator" +xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${SCHEME_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build +if [ "$?" != "0" ] then -xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build -else - -xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build +echo "[ERROR]: FAILED Step 1: Building for iPhoneSimulator"; +envExit 1 fi -open "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/" - - -# Step 1. Copy the framework structure (from iphoneos build) to the universal folder -echo "Copying to output folder: ${UNIVERSAL_OUTPUTFOLDER}/ from ${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME} " -cp -R "${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/" - -echo "will copy files" +echo "Step 2. Copy the framework structure (from iphoneos build) to the universal folder" +cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}" "${UNIVERSAL_OUTPUTFOLDER}/" +if [ "$?" != "0" ] +then +echo "[ERROR]: FAILED Step 2: Copy the framework structure (from iphoneos build) to the universal folder."; +envExit 1 +fi -# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory -SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/." +echo "Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory" +SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PRODUCT_NAME}.framework/Modules/${PRODUCT_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then -cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule" +cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PRODUCT_NAME}.framework/Modules/${PRODUCT_NAME}.swiftmodule" +if [ "$?" != "0" ] +then +echo "[ERROR]: FAILED Step 3: Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory"; +envExit 1 +fi fi -# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory -echo "Combining executables" - -#open "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/" - -lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}" - -open "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/" +echo "Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory" +lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${EXECUTABLE_PATH}" +if [ "$?" != "0" ] +then +echo "[ERROR]: FAILED Step 4: Create universal binary file using lipo and place the combined executable in the copied framework directory"; +envExit 1 +fi -# Step 4. Create universal binaries for embedded frameworks -#for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do -#BINARY_NAME="${SUB_FRAMEWORK%.*}" -#lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "$${TARGET_BUILD_DIR}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" -#done +echo "Step 5. Create universal binaries for embedded frameworks"; +FRAMEWORKS_DIR="${UNIVERSAL_OUTPUTFOLDER}/${PRODUCT_NAME}.framework/Frameworks"; +if [ -e "${FRAMEWORKS_DIR}" ] +then +for SUB_FRAMEWORK in $(ls "${FRAMEWORKS_DIR}") +do +BINARY_NAME="${SUB_FRAMEWORK%.*}" +lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PRODUCT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${PRODUCT_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" +if [ "$?" != "0" ] +then +echo "[ERROR]: FAILED Step 5 (${SUB_FRAMEWORK}): Create universal binaries for embedded frameworks"; +envExit 1 +fi +done +fi -# Step 5. Convenience step to copy the framework to the project's directory -echo "Copying to project dir" +echo "Step 6. Convenience step to copy the framework to the project's directory" +yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}" && \ +yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_FOLDER}" +if [ "$?" != "0" ] +then +echo "[ERROR]: FAILED Step 6: Convenience step to copy the framework to the project's directory"; +envExit 1; +fi -yes | cp -vRfL "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework" "${PROJECT_DIR}" +fi +} -open "${PROJECT_DIR}" +archiveFramework() { +echo "Step 7. Create a zip archive of the framework" +if [ ! -e "${PROJECT_FOLDER}/${IBSC_MODULE}.framework" ] +then +echo "[ERROR]: FAILED Step 7: ${IBSC_MODULE}/${PRODUCT_NAME}.framework doesn't exist"; +envExit 1; fi +cd "${PROJECT_FOLDER}" +#VERSION=$(grep s.version ../${PRODUCT_NAME}.podspec|grep -v s.source|grep -v cocoapods_version|sed 's/s.version//'|sed 's/[^\.,0-9]//g'); +zip -r "${IBSC_MODULE}-${TARGET_NAME}.framework.zip" "${IBSC_MODULE}.framework" +} + +# main function - delegates to the helpers +main() { +validate; +configure; +buildFramework; +archiveFramework; +open "${PROJECT_FOLDER}"; +} +main; diff --git a/wrappers/java/pom.xml b/wrappers/java/pom.xml index 50b0244d34..131e934000 100644 --- a/wrappers/java/pom.xml +++ b/wrappers/java/pom.xml @@ -5,7 +5,7 @@ org.hyperledger indy jar - 1.8.2 + 1.8.3 indy This is the official SDK for Hyperledger Indy (https://www.hyperledger.org/projects), which provides a distributed-ledger-based foundation for self-sovereign identity (https://sovrin.org). 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 b9ec84e135..9758b440f8 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 @@ -1274,8 +1274,8 @@ public static CompletableFuture getResponseMetadata( * @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 oldValue - (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). + * @param newValue - (Optional) 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. @@ -1342,7 +1342,7 @@ public static CompletableFuture buildAuthRuleRequest( * @param action - (Optional) type of action for which authentication rules will be applied. * Can be either "ADD" (to add new rule) or "EDIT" (to edit an existing one). * @param field - (Optional) transaction field for which authentication rule will be applied. - * @param oldValue - (Optional) old value of field, which can be changed to a new_value (must be specified for EDIT action). + * @param oldValue - (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). * @param newValue - (Optional) new value that can be used to fill the field. * * @return A future resolving to a request result as json. diff --git a/wrappers/nodejs/README.md b/wrappers/nodejs/README.md index fe62c35bc1..cd5cf075f6 100644 --- a/wrappers/nodejs/README.md +++ b/wrappers/nodejs/README.md @@ -1759,7 +1759,7 @@ Builds a AUTH_RULE request. Request to change authentication rules for a ledger * "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. +* `newValue`: String - \(Optional\) 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: ``` { @@ -1798,7 +1798,7 @@ NOTE: Either none or all transaction related parameters must be specified (`oldV * `txnType`: String - target ledger transaction alias or associated value. * `action`: String - target action type. Can be either "ADD" or "EDIT". * `field`: String - target transaction field. -* `oldValue`: String - \(Optional\) old value of field, which can be changed to a new_value (must be specified for EDIT action). +* `oldValue`: String - \(Optional\) old value of field, which can be changed to a new_value (mandatory for EDIT action). * `newValue`: String - \(Optional\) new value that can be used to fill the field. * __->__ `request`: Json diff --git a/wrappers/nodejs/package.json b/wrappers/nodejs/package.json index bceecfa037..1b77246f82 100644 --- a/wrappers/nodejs/package.json +++ b/wrappers/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "indy-sdk", - "version": "1.8.2", + "version": "1.8.3", "description": "Native bindings for hyperledger indy", "author": "hyperledger", "license": "Apache-2.0", diff --git a/wrappers/nodejs/test/ledger.js b/wrappers/nodejs/test/ledger.js index e73fa9c173..3096a1ec0d 100644 --- a/wrappers/nodejs/test/ledger.js +++ b/wrappers/nodejs/test/ledger.js @@ -154,7 +154,7 @@ test('ledger', async function (t) { // Auth Rule req = await indy.buildGetAuthRuleRequest(trusteeDid, 'NYM', 'ADD', 'role', null, '101') res = await indy.submitRequest(pool.handle, req) - var defaultConstraint = res['result']['data']['ADD--1--role--*--101'] + var defaultConstraint = res['result']['data']['1--ADD--role--*--101'] var constraint = { 'sig_count': 1, @@ -171,7 +171,7 @@ test('ledger', async function (t) { req = await indy.buildGetAuthRuleRequest(trusteeDid, 'NYM', 'ADD', 'role', null, '101') res = await indy.submitRequest(pool.handle, req) - t.deepEqual(res['result']['data']['ADD--1--role--*--101'], constraint) + t.deepEqual(res['result']['data']['1--ADD--role--*--101'], constraint) // set back req = await indy.buildAuthRuleRequest(trusteeDid, 'NYM', 'ADD', 'role', null, '101', defaultConstraint) diff --git a/wrappers/python/indy/ledger.py b/wrappers/python/indy/ledger.py index deffa53c2b..2ff5f7c42f 100644 --- a/wrappers/python/indy/ledger.py +++ b/wrappers/python/indy/ledger.py @@ -1268,7 +1268,7 @@ async def build_auth_rule_request(submitter_did: str, action: str, field: str, old_value: Optional[str], - new_value: str, + new_value: Optional[str], constraint: str) -> str: """ Builds a AUTH_RULE request. Request to change authentication rules for a ledger transaction. @@ -1278,8 +1278,8 @@ async def build_auth_rule_request(submitter_did: str, :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 old_value: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). + :param new_value: (Optional) 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. @@ -1322,7 +1322,7 @@ async def build_auth_rule_request(submitter_did: str, 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_new_value = c_char_p(new_value.encode('utf-8')) if new_value is not None else None c_constraint = c_char_p(constraint.encode('utf-8')) request_json = await do_call('indy_build_auth_rule_request', @@ -1357,8 +1357,8 @@ async def build_get_auth_rule_request(submitter_did: Optional[str], :param txn_type: target ledger transaction alias or associated value. :param action: target action type. Can be either "ADD" or "EDIT". :param field: target transaction field. - :param old_value: old value of field, which can be changed to a new_value (must be specified for EDIT action). - :param new_value: new value that can be used to fill the field. + :param old_value: (Optional) old value of field, which can be changed to a new_value (must be specified for EDIT action). + :param new_value: (Optional) new value that can be used to fill the field. :return: Request result as json. """ diff --git a/wrappers/python/setup.py b/wrappers/python/setup.py index b0ebc541fb..9a42932eae 100644 --- a/wrappers/python/setup.py +++ b/wrappers/python/setup.py @@ -1,7 +1,7 @@ from distutils.core import setup import os -PKG_VERSION = os.environ.get('PACKAGE_VERSION') or '1.8.2' +PKG_VERSION = os.environ.get('PACKAGE_VERSION') or '1.8.3' setup( name='python3-indy', diff --git a/wrappers/rust/Cargo.toml b/wrappers/rust/Cargo.toml index 76ca1c7fee..b3566a205e 100644 --- a/wrappers/rust/Cargo.toml +++ b/wrappers/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "indy" -version = "1.8.2" +version = "1.8.3" description = "A library for assisting developers using LibIndy API" authors = ["Mike Lodder ", "Matt Raffel ", @@ -29,7 +29,7 @@ lazy_static = "0.2" log = { version = "0.4.1", features = ["std"] } num-traits = "0.2" num-derive = "0.2" -indy-sys = { path ="indy-sys", version = "=1.8.2" } +indy-sys = { path ="indy-sys", version = "=1.8.3" } libc = "=0.2.41" serde_json = "1.0.22" serde_derive = "1.0.76" diff --git a/wrappers/rust/indy-sys/Cargo.toml b/wrappers/rust/indy-sys/Cargo.toml index d5de13217e..71d16fe4bf 100644 --- a/wrappers/rust/indy-sys/Cargo.toml +++ b/wrappers/rust/indy-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "indy-sys" description = "FFI bindings to Libindy C API" -version = "1.8.2" +version = "1.8.3" authors = ["Mike Lodder "] build = "build.rs" links = "indy" diff --git a/wrappers/rust/indy-sys/src/lib.rs b/wrappers/rust/indy-sys/src/lib.rs index 6d475c4f8e..7db0d03929 100644 --- a/wrappers/rust/indy-sys/src/lib.rs +++ b/wrappers/rust/indy-sys/src/lib.rs @@ -21,7 +21,7 @@ pub type Handle = i32; pub type Error = i32; pub type ResponseEmptyCB = extern fn(xcommand_handle: Handle, err: Error); -pub type ResponseBoolCB = extern fn(xcommand_handle: Handle, err: Error, bool1: u8); +pub type ResponseBoolCB = extern fn(xcommand_handle: Handle, err: Error, bool1: bool); pub type ResponseI32CB = extern fn(xcommand_handle: Handle, err: Error, handle: Handle); pub type ResponseI32UsizeCB = extern fn(xcommand_handle: Handle, err: Error, handle: Handle, total_count: usize); pub type ResponseStringCB = extern fn(xcommand_handle: Handle, err: Error, str1: CString); diff --git a/wrappers/rust/src/ledger.rs b/wrappers/rust/src/ledger.rs index fed8c6ef80..1e67f8d0f4 100644 --- a/wrappers/rust/src/ledger.rs +++ b/wrappers/rust/src/ledger.rs @@ -1001,8 +1001,8 @@ fn _get_response_metadata(command_handle: IndyHandle, response: &str, cb: Option /// * `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. +/// * `old_value`: (Optional) old value of a field, which can be changed to a new_value (mandatory for EDIT action). +/// * `new_value`:(Optional) 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. @@ -1021,7 +1021,7 @@ fn _get_response_metadata(command_handle: IndyHandle, response: &str, cb: Option /// # 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> { + old_value: Option<&str>, new_value: Option<&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); @@ -1035,17 +1035,17 @@ fn _build_auth_rule_request(command_handle: IndyHandle, action: &str, field: &str, old_value: Option<&str>, - new_value: &str, + new_value: Option<&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); + let new_value_str = opt_c_str!(new_value); ErrorCode::from(unsafe { ledger::indy_build_auth_rule_request(command_handle, @@ -1054,7 +1054,7 @@ fn _build_auth_rule_request(command_handle: IndyHandle, action.as_ptr(), field.as_ptr(), opt_c_ptr!(old_value, old_value_str), - new_value.as_ptr(), + opt_c_ptr!(new_value, new_value_str), constraint.as_ptr(), cb) }) @@ -1067,11 +1067,11 @@ fn _build_auth_rule_request(command_handle: IndyHandle, /// * all - to get authentication rules for specific action (`old_value` can be skipped for `ADD` action) /// /// # Arguments -/// * `txn_type`: target ledger transaction alias or associated value. -/// * `action`: target action type. Can be either "ADD" or "EDIT". -/// * `field`: target transaction field. -/// * `old_value`: old value of field, which can be changed to a new_value (must be specified for EDIT action). -/// * `new_value`: new value that can be used to fill the field. +/// * `txn_type`: (Optional) target ledger transaction alias or associated value. +/// * `action`: (Optional) target action type. Can be either "ADD" or "EDIT". +/// * `field`: (Optional) target transaction field. +/// * `old_value`: (Optional) old value of field, which can be changed to a new_value (mandatory for EDIT action). +/// * `new_value`: (Optional) new value that can be used to fill the field. /// /// # Returns /// Request result as json. diff --git a/wrappers/rust/src/utils/callbacks.rs b/wrappers/rust/src/utils/callbacks.rs index 39fbb6cf79..a7f236269d 100644 --- a/wrappers/rust/src/utils/callbacks.rs +++ b/wrappers/rust/src/utils/callbacks.rs @@ -97,7 +97,7 @@ impl ClosureHandler { CALLBACKS_STR_SLICE, (rust_str!(str), rust_slice!(data, len).to_owned())); - cb_ec!(cb_ec_bool(b: u8)->bool, CALLBACKS_BOOL, b > 0); + cb_ec!(cb_ec_bool(b: bool)->bool, CALLBACKS_BOOL, b); } macro_rules! result_handler { diff --git a/wrappers/rust/tests/ledger.rs b/wrappers/rust/tests/ledger.rs index e54a79418c..2eb383b8c3 100644 --- a/wrappers/rust/tests/ledger.rs +++ b/wrappers/rust/tests/ledger.rs @@ -632,7 +632,7 @@ mod test_build_auth_rule_request { &ADD_AUTH_ACTION, FIELD, None, - NEW_VALUE, + Some(NEW_VALUE), ROLE_CONSTRAINT).wait().unwrap(); }